]> Git Repo - qemu.git/blame - target-mips/op_helper.c
target-mips: correct MFC0 for CP0.EntryLo in MIPS64
[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
895c2d04 1071void helper_mtc0_entrylo0(CPUMIPSState *env, target_ulong arg1)
f1aa6320
TS
1072{
1073 /* Large physaddr (PABITS) not implemented */
1074 /* 1k pages not implemented */
7207c7f9
LA
1075 target_ulong rxi = arg1 & (env->CP0_PageGrain & (3u << CP0PG_XIE));
1076 env->CP0_EntryLo0 = (arg1 & 0x3FFFFFFF) | (rxi << (CP0EnLo_XI - 30));
f1aa6320
TS
1077}
1078
7207c7f9
LA
1079#if defined(TARGET_MIPS64)
1080void helper_dmtc0_entrylo0(CPUMIPSState *env, uint64_t arg1)
1081{
1082 uint64_t rxi = arg1 & ((env->CP0_PageGrain & (3ull << CP0PG_XIE)) << 32);
1083 env->CP0_EntryLo0 = (arg1 & 0x3FFFFFFF) | rxi;
1084}
1085#endif
1086
895c2d04 1087void helper_mtc0_tcstatus(CPUMIPSState *env, target_ulong arg1)
f1aa6320
TS
1088{
1089 uint32_t mask = env->CP0_TCStatus_rw_bitmask;
1090 uint32_t newval;
1091
d9bea114 1092 newval = (env->active_tc.CP0_TCStatus & ~mask) | (arg1 & mask);
f1aa6320 1093
b5dc7732 1094 env->active_tc.CP0_TCStatus = newval;
fe8dca8c 1095 sync_c0_tcstatus(env, env->current_tc, newval);
f1aa6320
TS
1096}
1097
895c2d04 1098void helper_mttc0_tcstatus(CPUMIPSState *env, target_ulong arg1)
f1aa6320
TS
1099{
1100 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1101 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320 1102
b93bbdcd
EI
1103 if (other_tc == other->current_tc)
1104 other->active_tc.CP0_TCStatus = arg1;
b5dc7732 1105 else
b93bbdcd 1106 other->tcs[other_tc].CP0_TCStatus = arg1;
fe8dca8c 1107 sync_c0_tcstatus(other, other_tc, arg1);
f1aa6320
TS
1108}
1109
895c2d04 1110void helper_mtc0_tcbind(CPUMIPSState *env, target_ulong arg1)
f1aa6320
TS
1111{
1112 uint32_t mask = (1 << CP0TCBd_TBE);
1113 uint32_t newval;
1114
1115 if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
1116 mask |= (1 << CP0TCBd_CurVPE);
d9bea114 1117 newval = (env->active_tc.CP0_TCBind & ~mask) | (arg1 & mask);
b5dc7732 1118 env->active_tc.CP0_TCBind = newval;
f1aa6320
TS
1119}
1120
895c2d04 1121void helper_mttc0_tcbind(CPUMIPSState *env, target_ulong arg1)
f1aa6320
TS
1122{
1123 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1124 uint32_t mask = (1 << CP0TCBd_TBE);
1125 uint32_t newval;
895c2d04 1126 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320 1127
b93bbdcd 1128 if (other->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
f1aa6320 1129 mask |= (1 << CP0TCBd_CurVPE);
b93bbdcd
EI
1130 if (other_tc == other->current_tc) {
1131 newval = (other->active_tc.CP0_TCBind & ~mask) | (arg1 & mask);
1132 other->active_tc.CP0_TCBind = newval;
b5dc7732 1133 } else {
b93bbdcd
EI
1134 newval = (other->tcs[other_tc].CP0_TCBind & ~mask) | (arg1 & mask);
1135 other->tcs[other_tc].CP0_TCBind = newval;
b5dc7732 1136 }
f1aa6320
TS
1137}
1138
895c2d04 1139void helper_mtc0_tcrestart(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1140{
d9bea114 1141 env->active_tc.PC = arg1;
b5dc7732 1142 env->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
5499b6ff 1143 env->lladdr = 0ULL;
f1aa6320
TS
1144 /* MIPS16 not implemented. */
1145}
1146
895c2d04 1147void helper_mttc0_tcrestart(CPUMIPSState *env, target_ulong arg1)
f1aa6320
TS
1148{
1149 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1150 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320 1151
b93bbdcd
EI
1152 if (other_tc == other->current_tc) {
1153 other->active_tc.PC = arg1;
1154 other->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
1155 other->lladdr = 0ULL;
b5dc7732
TS
1156 /* MIPS16 not implemented. */
1157 } else {
b93bbdcd
EI
1158 other->tcs[other_tc].PC = arg1;
1159 other->tcs[other_tc].CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
1160 other->lladdr = 0ULL;
b5dc7732
TS
1161 /* MIPS16 not implemented. */
1162 }
f1aa6320
TS
1163}
1164
895c2d04 1165void helper_mtc0_tchalt(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1166{
135dd63a
AF
1167 MIPSCPU *cpu = mips_env_get_cpu(env);
1168
d9bea114 1169 env->active_tc.CP0_TCHalt = arg1 & 0x1;
f1aa6320
TS
1170
1171 // TODO: Halt TC / Restart (if allocated+active) TC.
f249412c 1172 if (env->active_tc.CP0_TCHalt & 1) {
c6679e90 1173 mips_tc_sleep(cpu, env->current_tc);
f249412c 1174 } else {
135dd63a 1175 mips_tc_wake(cpu, env->current_tc);
f249412c 1176 }
f1aa6320
TS
1177}
1178
895c2d04 1179void helper_mttc0_tchalt(CPUMIPSState *env, target_ulong arg1)
f1aa6320
TS
1180{
1181 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1182 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
135dd63a 1183 MIPSCPU *other_cpu = mips_env_get_cpu(other);
f1aa6320
TS
1184
1185 // TODO: Halt TC / Restart (if allocated+active) TC.
1186
b93bbdcd
EI
1187 if (other_tc == other->current_tc)
1188 other->active_tc.CP0_TCHalt = arg1;
b5dc7732 1189 else
b93bbdcd 1190 other->tcs[other_tc].CP0_TCHalt = arg1;
f249412c
EI
1191
1192 if (arg1 & 1) {
c6679e90 1193 mips_tc_sleep(other_cpu, other_tc);
f249412c 1194 } else {
135dd63a 1195 mips_tc_wake(other_cpu, other_tc);
f249412c 1196 }
f1aa6320
TS
1197}
1198
895c2d04 1199void helper_mtc0_tccontext(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1200{
d9bea114 1201 env->active_tc.CP0_TCContext = arg1;
f1aa6320
TS
1202}
1203
895c2d04 1204void helper_mttc0_tccontext(CPUMIPSState *env, target_ulong arg1)
f1aa6320
TS
1205{
1206 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1207 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320 1208
b93bbdcd
EI
1209 if (other_tc == other->current_tc)
1210 other->active_tc.CP0_TCContext = arg1;
b5dc7732 1211 else
b93bbdcd 1212 other->tcs[other_tc].CP0_TCContext = arg1;
f1aa6320
TS
1213}
1214
895c2d04 1215void helper_mtc0_tcschedule(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1216{
d9bea114 1217 env->active_tc.CP0_TCSchedule = arg1;
f1aa6320
TS
1218}
1219
895c2d04 1220void helper_mttc0_tcschedule(CPUMIPSState *env, target_ulong arg1)
f1aa6320
TS
1221{
1222 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1223 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320 1224
b93bbdcd
EI
1225 if (other_tc == other->current_tc)
1226 other->active_tc.CP0_TCSchedule = arg1;
b5dc7732 1227 else
b93bbdcd 1228 other->tcs[other_tc].CP0_TCSchedule = arg1;
f1aa6320
TS
1229}
1230
895c2d04 1231void helper_mtc0_tcschefback(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1232{
d9bea114 1233 env->active_tc.CP0_TCScheFBack = arg1;
f1aa6320
TS
1234}
1235
895c2d04 1236void helper_mttc0_tcschefback(CPUMIPSState *env, target_ulong arg1)
f1aa6320
TS
1237{
1238 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1239 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320 1240
b93bbdcd
EI
1241 if (other_tc == other->current_tc)
1242 other->active_tc.CP0_TCScheFBack = arg1;
b5dc7732 1243 else
b93bbdcd 1244 other->tcs[other_tc].CP0_TCScheFBack = arg1;
f1aa6320
TS
1245}
1246
895c2d04 1247void helper_mtc0_entrylo1(CPUMIPSState *env, target_ulong arg1)
f1aa6320
TS
1248{
1249 /* Large physaddr (PABITS) not implemented */
1250 /* 1k pages not implemented */
7207c7f9
LA
1251 target_ulong rxi = arg1 & (env->CP0_PageGrain & (3u << CP0PG_XIE));
1252 env->CP0_EntryLo1 = (arg1 & 0x3FFFFFFF) | (rxi << (CP0EnLo_XI - 30));
f1aa6320
TS
1253}
1254
7207c7f9
LA
1255#if defined(TARGET_MIPS64)
1256void helper_dmtc0_entrylo1(CPUMIPSState *env, uint64_t arg1)
1257{
1258 uint64_t rxi = arg1 & ((env->CP0_PageGrain & (3ull << CP0PG_XIE)) << 32);
1259 env->CP0_EntryLo1 = (arg1 & 0x3FFFFFFF) | rxi;
1260}
1261#endif
1262
895c2d04 1263void helper_mtc0_context(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1264{
d9bea114 1265 env->CP0_Context = (env->CP0_Context & 0x007FFFFF) | (arg1 & ~0x007FFFFF);
f1aa6320
TS
1266}
1267
895c2d04 1268void helper_mtc0_pagemask(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1269{
ba801af4
LA
1270 uint64_t mask = arg1 >> (TARGET_PAGE_BITS + 1);
1271 if (!(env->insn_flags & ISA_MIPS32R6) || (arg1 == ~0) ||
1272 (mask == 0x0000 || mask == 0x0003 || mask == 0x000F ||
1273 mask == 0x003F || mask == 0x00FF || mask == 0x03FF ||
1274 mask == 0x0FFF || mask == 0x3FFF || mask == 0xFFFF)) {
1275 env->CP0_PageMask = arg1 & (0x1FFFFFFF & (TARGET_PAGE_MASK << 1));
1276 }
f1aa6320
TS
1277}
1278
895c2d04 1279void helper_mtc0_pagegrain(CPUMIPSState *env, target_ulong arg1)
f1aa6320
TS
1280{
1281 /* SmartMIPS not implemented */
1282 /* Large physaddr (PABITS) not implemented */
1283 /* 1k pages not implemented */
7207c7f9
LA
1284 env->CP0_PageGrain = (arg1 & env->CP0_PageGrain_rw_bitmask) |
1285 (env->CP0_PageGrain & ~env->CP0_PageGrain_rw_bitmask);
f1aa6320
TS
1286}
1287
895c2d04 1288void helper_mtc0_wired(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1289{
ba801af4
LA
1290 if (env->insn_flags & ISA_MIPS32R6) {
1291 if (arg1 < env->tlb->nb_tlb) {
1292 env->CP0_Wired = arg1;
1293 }
1294 } else {
1295 env->CP0_Wired = arg1 % env->tlb->nb_tlb;
1296 }
f1aa6320
TS
1297}
1298
895c2d04 1299void helper_mtc0_srsconf0(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1300{
d9bea114 1301 env->CP0_SRSConf0 |= arg1 & env->CP0_SRSConf0_rw_bitmask;
f1aa6320
TS
1302}
1303
895c2d04 1304void helper_mtc0_srsconf1(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1305{
d9bea114 1306 env->CP0_SRSConf1 |= arg1 & env->CP0_SRSConf1_rw_bitmask;
f1aa6320
TS
1307}
1308
895c2d04 1309void helper_mtc0_srsconf2(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1310{
d9bea114 1311 env->CP0_SRSConf2 |= arg1 & env->CP0_SRSConf2_rw_bitmask;
f1aa6320
TS
1312}
1313
895c2d04 1314void helper_mtc0_srsconf3(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1315{
d9bea114 1316 env->CP0_SRSConf3 |= arg1 & env->CP0_SRSConf3_rw_bitmask;
f1aa6320
TS
1317}
1318
895c2d04 1319void helper_mtc0_srsconf4(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1320{
d9bea114 1321 env->CP0_SRSConf4 |= arg1 & env->CP0_SRSConf4_rw_bitmask;
f1aa6320
TS
1322}
1323
895c2d04 1324void helper_mtc0_hwrena(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1325{
d279279e
PJ
1326 uint32_t mask = 0x0000000F;
1327
1328 if (env->CP0_Config3 & (1 << CP0C3_ULRI)) {
1329 mask |= (1 << 29);
1330
1331 if (arg1 & (1 << 29)) {
1332 env->hflags |= MIPS_HFLAG_HWRENA_ULR;
1333 } else {
1334 env->hflags &= ~MIPS_HFLAG_HWRENA_ULR;
1335 }
1336 }
1337
1338 env->CP0_HWREna = arg1 & mask;
f1aa6320
TS
1339}
1340
895c2d04 1341void helper_mtc0_count(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1342{
d9bea114 1343 cpu_mips_store_count(env, arg1);
f1aa6320
TS
1344}
1345
895c2d04 1346void helper_mtc0_entryhi(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1347{
9456c2fb
LA
1348 target_ulong old, val, mask;
1349 mask = (TARGET_PAGE_MASK << 1) | 0xFF;
1350 if (((env->CP0_Config4 >> CP0C4_IE) & 0x3) >= 2) {
1351 mask |= 1 << CP0EnHi_EHINV;
1352 }
f1aa6320
TS
1353
1354 /* 1k pages not implemented */
f1aa6320 1355#if defined(TARGET_MIPS64)
ba801af4
LA
1356 if (env->insn_flags & ISA_MIPS32R6) {
1357 int entryhi_r = extract64(arg1, 62, 2);
1358 int config0_at = extract32(env->CP0_Config0, 13, 2);
1359 bool no_supervisor = (env->CP0_Status_rw_bitmask & 0x8) == 0;
1360 if ((entryhi_r == 2) ||
1361 (entryhi_r == 1 && (no_supervisor || config0_at == 1))) {
1362 /* skip EntryHi.R field if new value is reserved */
1363 mask &= ~(0x3ull << 62);
1364 }
1365 }
1366 mask &= env->SEGMask;
f1aa6320
TS
1367#endif
1368 old = env->CP0_EntryHi;
ba801af4 1369 val = (arg1 & mask) | (old & ~mask);
f1aa6320
TS
1370 env->CP0_EntryHi = val;
1371 if (env->CP0_Config3 & (1 << CP0C3_MT)) {
fe8dca8c 1372 sync_c0_entryhi(env, env->current_tc);
f1aa6320
TS
1373 }
1374 /* If the ASID changes, flush qemu's TLB. */
1375 if ((old & 0xFF) != (val & 0xFF))
1376 cpu_mips_tlb_flush(env, 1);
1377}
1378
895c2d04 1379void helper_mttc0_entryhi(CPUMIPSState *env, target_ulong arg1)
f1aa6320
TS
1380{
1381 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1382 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320 1383
fe8dca8c
EI
1384 other->CP0_EntryHi = arg1;
1385 sync_c0_entryhi(other, other_tc);
f1aa6320
TS
1386}
1387
895c2d04 1388void helper_mtc0_compare(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1389{
d9bea114 1390 cpu_mips_store_compare(env, arg1);
f1aa6320
TS
1391}
1392
895c2d04 1393void helper_mtc0_status(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1394{
a47dddd7 1395 MIPSCPU *cpu = mips_env_get_cpu(env);
f1aa6320 1396 uint32_t val, old;
ba801af4 1397
f1aa6320 1398 old = env->CP0_Status;
81a423e6
MR
1399 cpu_mips_store_status(env, arg1);
1400 val = env->CP0_Status;
fe8dca8c 1401
c01fccd2
AJ
1402 if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
1403 qemu_log("Status %08x (%08x) => %08x (%08x) Cause %08x",
1404 old, old & env->CP0_Cause & CP0Ca_IP_mask,
1405 val, val & env->CP0_Cause & CP0Ca_IP_mask,
1406 env->CP0_Cause);
1407 switch (env->hflags & MIPS_HFLAG_KSU) {
1408 case MIPS_HFLAG_UM: qemu_log(", UM\n"); break;
1409 case MIPS_HFLAG_SM: qemu_log(", SM\n"); break;
1410 case MIPS_HFLAG_KM: qemu_log("\n"); break;
a47dddd7
AF
1411 default:
1412 cpu_abort(CPU(cpu), "Invalid MMU mode!\n");
1413 break;
31e3104f 1414 }
c01fccd2 1415 }
f1aa6320
TS
1416}
1417
895c2d04 1418void helper_mttc0_status(CPUMIPSState *env, target_ulong arg1)
f1aa6320
TS
1419{
1420 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1d725ae9 1421 uint32_t mask = env->CP0_Status_rw_bitmask & ~0xf1000018;
895c2d04 1422 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320 1423
1d725ae9 1424 other->CP0_Status = (other->CP0_Status & ~mask) | (arg1 & mask);
895c2d04 1425 sync_c0_status(env, other, other_tc);
f1aa6320
TS
1426}
1427
895c2d04 1428void helper_mtc0_intctl(CPUMIPSState *env, target_ulong arg1)
f1aa6320
TS
1429{
1430 /* vectored interrupts not implemented, no performance counters. */
bc45a67a 1431 env->CP0_IntCtl = (env->CP0_IntCtl & ~0x000003e0) | (arg1 & 0x000003e0);
f1aa6320
TS
1432}
1433
895c2d04 1434void helper_mtc0_srsctl(CPUMIPSState *env, target_ulong arg1)
f1aa6320
TS
1435{
1436 uint32_t mask = (0xf << CP0SRSCtl_ESS) | (0xf << CP0SRSCtl_PSS);
d9bea114 1437 env->CP0_SRSCtl = (env->CP0_SRSCtl & ~mask) | (arg1 & mask);
f1aa6320
TS
1438}
1439
895c2d04 1440void helper_mtc0_cause(CPUMIPSState *env, target_ulong arg1)
5a25ce94 1441{
81a423e6 1442 cpu_mips_store_cause(env, arg1);
5a25ce94
EI
1443}
1444
895c2d04 1445void helper_mttc0_cause(CPUMIPSState *env, target_ulong arg1)
5a25ce94
EI
1446{
1447 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1448 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
5a25ce94 1449
81a423e6 1450 cpu_mips_store_cause(other, arg1);
5a25ce94
EI
1451}
1452
895c2d04 1453target_ulong helper_mftc0_epc(CPUMIPSState *env)
5a25ce94
EI
1454{
1455 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1456 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
5a25ce94
EI
1457
1458 return other->CP0_EPC;
1459}
1460
895c2d04 1461target_ulong helper_mftc0_ebase(CPUMIPSState *env)
5a25ce94
EI
1462{
1463 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1464 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
5a25ce94
EI
1465
1466 return other->CP0_EBase;
1467}
1468
895c2d04 1469void helper_mtc0_ebase(CPUMIPSState *env, target_ulong arg1)
f1aa6320
TS
1470{
1471 /* vectored interrupts not implemented */
671b0f36 1472 env->CP0_EBase = (env->CP0_EBase & ~0x3FFFF000) | (arg1 & 0x3FFFF000);
f1aa6320
TS
1473}
1474
895c2d04 1475void helper_mttc0_ebase(CPUMIPSState *env, target_ulong arg1)
5a25ce94
EI
1476{
1477 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1478 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
5a25ce94
EI
1479 other->CP0_EBase = (other->CP0_EBase & ~0x3FFFF000) | (arg1 & 0x3FFFF000);
1480}
1481
895c2d04 1482target_ulong helper_mftc0_configx(CPUMIPSState *env, target_ulong idx)
5a25ce94
EI
1483{
1484 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1485 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
5a25ce94
EI
1486
1487 switch (idx) {
1488 case 0: return other->CP0_Config0;
1489 case 1: return other->CP0_Config1;
1490 case 2: return other->CP0_Config2;
1491 case 3: return other->CP0_Config3;
1492 /* 4 and 5 are reserved. */
1493 case 6: return other->CP0_Config6;
1494 case 7: return other->CP0_Config7;
1495 default:
1496 break;
1497 }
1498 return 0;
1499}
1500
895c2d04 1501void helper_mtc0_config0(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1502{
d9bea114 1503 env->CP0_Config0 = (env->CP0_Config0 & 0x81FFFFF8) | (arg1 & 0x00000007);
f1aa6320
TS
1504}
1505
895c2d04 1506void helper_mtc0_config2(CPUMIPSState *env, target_ulong arg1)
f1aa6320
TS
1507{
1508 /* tertiary/secondary caches not implemented */
1509 env->CP0_Config2 = (env->CP0_Config2 & 0x8FFF0FFF);
1510}
1511
90f12d73
MR
1512void helper_mtc0_config3(CPUMIPSState *env, target_ulong arg1)
1513{
1514 if (env->insn_flags & ASE_MICROMIPS) {
1515 env->CP0_Config3 = (env->CP0_Config3 & ~(1 << CP0C3_ISA_ON_EXC)) |
1516 (arg1 & (1 << CP0C3_ISA_ON_EXC));
1517 }
1518}
1519
b4160af1
PJ
1520void helper_mtc0_config4(CPUMIPSState *env, target_ulong arg1)
1521{
1522 env->CP0_Config4 = (env->CP0_Config4 & (~env->CP0_Config4_rw_bitmask)) |
1523 (arg1 & env->CP0_Config4_rw_bitmask);
1524}
1525
b4dd99a3
PJ
1526void helper_mtc0_config5(CPUMIPSState *env, target_ulong arg1)
1527{
1528 env->CP0_Config5 = (env->CP0_Config5 & (~env->CP0_Config5_rw_bitmask)) |
1529 (arg1 & env->CP0_Config5_rw_bitmask);
e97a391d 1530 compute_hflags(env);
b4dd99a3
PJ
1531}
1532
895c2d04 1533void helper_mtc0_lladdr(CPUMIPSState *env, target_ulong arg1)
2a6e32dd
AJ
1534{
1535 target_long mask = env->CP0_LLAddr_rw_bitmask;
1536 arg1 = arg1 << env->CP0_LLAddr_shift;
1537 env->lladdr = (env->lladdr & ~mask) | (arg1 & mask);
1538}
1539
895c2d04 1540void helper_mtc0_watchlo(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
f1aa6320
TS
1541{
1542 /* Watch exceptions for instructions, data loads, data stores
1543 not implemented. */
d9bea114 1544 env->CP0_WatchLo[sel] = (arg1 & ~0x7);
f1aa6320
TS
1545}
1546
895c2d04 1547void helper_mtc0_watchhi(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
f1aa6320 1548{
d9bea114
AJ
1549 env->CP0_WatchHi[sel] = (arg1 & 0x40FF0FF8);
1550 env->CP0_WatchHi[sel] &= ~(env->CP0_WatchHi[sel] & arg1 & 0x7);
f1aa6320
TS
1551}
1552
895c2d04 1553void helper_mtc0_xcontext(CPUMIPSState *env, target_ulong arg1)
f1aa6320
TS
1554{
1555 target_ulong mask = (1ULL << (env->SEGBITS - 7)) - 1;
d9bea114 1556 env->CP0_XContext = (env->CP0_XContext & mask) | (arg1 & ~mask);
f1aa6320
TS
1557}
1558
895c2d04 1559void helper_mtc0_framemask(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1560{
d9bea114 1561 env->CP0_Framemask = arg1; /* XXX */
f1aa6320
TS
1562}
1563
895c2d04 1564void helper_mtc0_debug(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1565{
d9bea114
AJ
1566 env->CP0_Debug = (env->CP0_Debug & 0x8C03FC1F) | (arg1 & 0x13300120);
1567 if (arg1 & (1 << CP0DB_DM))
f1aa6320
TS
1568 env->hflags |= MIPS_HFLAG_DM;
1569 else
1570 env->hflags &= ~MIPS_HFLAG_DM;
1571}
1572
895c2d04 1573void helper_mttc0_debug(CPUMIPSState *env, target_ulong arg1)
f1aa6320
TS
1574{
1575 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
d9bea114 1576 uint32_t val = arg1 & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt));
895c2d04 1577 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320
TS
1578
1579 /* XXX: Might be wrong, check with EJTAG spec. */
b93bbdcd
EI
1580 if (other_tc == other->current_tc)
1581 other->active_tc.CP0_Debug_tcstatus = val;
b5dc7732 1582 else
b93bbdcd
EI
1583 other->tcs[other_tc].CP0_Debug_tcstatus = val;
1584 other->CP0_Debug = (other->CP0_Debug &
1585 ((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
d9bea114 1586 (arg1 & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
f1aa6320
TS
1587}
1588
895c2d04 1589void helper_mtc0_performance0(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1590{
d9bea114 1591 env->CP0_Performance0 = arg1 & 0x000007ff;
f1aa6320
TS
1592}
1593
895c2d04 1594void helper_mtc0_taglo(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1595{
d9bea114 1596 env->CP0_TagLo = arg1 & 0xFFFFFCF6;
f1aa6320
TS
1597}
1598
895c2d04 1599void helper_mtc0_datalo(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1600{
d9bea114 1601 env->CP0_DataLo = arg1; /* XXX */
f1aa6320
TS
1602}
1603
895c2d04 1604void helper_mtc0_taghi(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1605{
d9bea114 1606 env->CP0_TagHi = arg1; /* XXX */
f1aa6320
TS
1607}
1608
895c2d04 1609void helper_mtc0_datahi(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1610{
d9bea114 1611 env->CP0_DataHi = arg1; /* XXX */
f1aa6320
TS
1612}
1613
f1aa6320 1614/* MIPS MT functions */
895c2d04 1615target_ulong helper_mftgpr(CPUMIPSState *env, uint32_t sel)
f1aa6320
TS
1616{
1617 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1618 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320 1619
b93bbdcd
EI
1620 if (other_tc == other->current_tc)
1621 return other->active_tc.gpr[sel];
b5dc7732 1622 else
b93bbdcd 1623 return other->tcs[other_tc].gpr[sel];
f1aa6320
TS
1624}
1625
895c2d04 1626target_ulong helper_mftlo(CPUMIPSState *env, uint32_t sel)
f1aa6320
TS
1627{
1628 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1629 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320 1630
b93bbdcd
EI
1631 if (other_tc == other->current_tc)
1632 return other->active_tc.LO[sel];
b5dc7732 1633 else
b93bbdcd 1634 return other->tcs[other_tc].LO[sel];
f1aa6320
TS
1635}
1636
895c2d04 1637target_ulong helper_mfthi(CPUMIPSState *env, uint32_t sel)
f1aa6320
TS
1638{
1639 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1640 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320 1641
b93bbdcd
EI
1642 if (other_tc == other->current_tc)
1643 return other->active_tc.HI[sel];
b5dc7732 1644 else
b93bbdcd 1645 return other->tcs[other_tc].HI[sel];
f1aa6320
TS
1646}
1647
895c2d04 1648target_ulong helper_mftacx(CPUMIPSState *env, uint32_t sel)
f1aa6320
TS
1649{
1650 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1651 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320 1652
b93bbdcd
EI
1653 if (other_tc == other->current_tc)
1654 return other->active_tc.ACX[sel];
b5dc7732 1655 else
b93bbdcd 1656 return other->tcs[other_tc].ACX[sel];
f1aa6320
TS
1657}
1658
895c2d04 1659target_ulong helper_mftdsp(CPUMIPSState *env)
f1aa6320
TS
1660{
1661 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1662 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320 1663
b93bbdcd
EI
1664 if (other_tc == other->current_tc)
1665 return other->active_tc.DSPControl;
b5dc7732 1666 else
b93bbdcd 1667 return other->tcs[other_tc].DSPControl;
f1aa6320 1668}
6af0bf9c 1669
895c2d04 1670void helper_mttgpr(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
f1aa6320
TS
1671{
1672 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1673 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320 1674
b93bbdcd
EI
1675 if (other_tc == other->current_tc)
1676 other->active_tc.gpr[sel] = arg1;
b5dc7732 1677 else
b93bbdcd 1678 other->tcs[other_tc].gpr[sel] = arg1;
f1aa6320
TS
1679}
1680
895c2d04 1681void helper_mttlo(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
f1aa6320
TS
1682{
1683 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1684 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320 1685
b93bbdcd
EI
1686 if (other_tc == other->current_tc)
1687 other->active_tc.LO[sel] = arg1;
b5dc7732 1688 else
b93bbdcd 1689 other->tcs[other_tc].LO[sel] = arg1;
f1aa6320
TS
1690}
1691
895c2d04 1692void helper_mtthi(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
f1aa6320
TS
1693{
1694 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1695 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320 1696
b93bbdcd
EI
1697 if (other_tc == other->current_tc)
1698 other->active_tc.HI[sel] = arg1;
b5dc7732 1699 else
b93bbdcd 1700 other->tcs[other_tc].HI[sel] = arg1;
f1aa6320
TS
1701}
1702
895c2d04 1703void helper_mttacx(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
f1aa6320
TS
1704{
1705 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1706 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320 1707
b93bbdcd
EI
1708 if (other_tc == other->current_tc)
1709 other->active_tc.ACX[sel] = arg1;
b5dc7732 1710 else
b93bbdcd 1711 other->tcs[other_tc].ACX[sel] = arg1;
f1aa6320
TS
1712}
1713
895c2d04 1714void helper_mttdsp(CPUMIPSState *env, target_ulong arg1)
f1aa6320
TS
1715{
1716 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1717 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320 1718
b93bbdcd
EI
1719 if (other_tc == other->current_tc)
1720 other->active_tc.DSPControl = arg1;
b5dc7732 1721 else
b93bbdcd 1722 other->tcs[other_tc].DSPControl = arg1;
f1aa6320
TS
1723}
1724
1725/* MIPS MT functions */
9ed5726c 1726target_ulong helper_dmt(void)
f1aa6320
TS
1727{
1728 // TODO
9ed5726c 1729 return 0;
f1aa6320
TS
1730}
1731
9ed5726c 1732target_ulong helper_emt(void)
f1aa6320
TS
1733{
1734 // TODO
9ed5726c 1735 return 0;
f1aa6320
TS
1736}
1737
895c2d04 1738target_ulong helper_dvpe(CPUMIPSState *env)
f1aa6320 1739{
182735ef 1740 CPUState *other_cs = first_cpu;
f249412c
EI
1741 target_ulong prev = env->mvp->CP0_MVPControl;
1742
bdc44640 1743 CPU_FOREACH(other_cs) {
182735ef 1744 MIPSCPU *other_cpu = MIPS_CPU(other_cs);
f249412c 1745 /* Turn off all VPEs except the one executing the dvpe. */
182735ef
AF
1746 if (&other_cpu->env != env) {
1747 other_cpu->env.mvp->CP0_MVPControl &= ~(1 << CP0MVPCo_EVP);
6f4d6b09 1748 mips_vpe_sleep(other_cpu);
f249412c 1749 }
bdc44640 1750 }
f249412c 1751 return prev;
f1aa6320
TS
1752}
1753
895c2d04 1754target_ulong helper_evpe(CPUMIPSState *env)
f1aa6320 1755{
182735ef 1756 CPUState *other_cs = first_cpu;
f249412c
EI
1757 target_ulong prev = env->mvp->CP0_MVPControl;
1758
bdc44640 1759 CPU_FOREACH(other_cs) {
182735ef 1760 MIPSCPU *other_cpu = MIPS_CPU(other_cs);
b35d77d7 1761
182735ef 1762 if (&other_cpu->env != env
81bad50e 1763 /* If the VPE is WFI, don't disturb its sleep. */
b35d77d7 1764 && !mips_vpe_is_wfi(other_cpu)) {
f249412c 1765 /* Enable the VPE. */
182735ef 1766 other_cpu->env.mvp->CP0_MVPControl |= (1 << CP0MVPCo_EVP);
c3affe56 1767 mips_vpe_wake(other_cpu); /* And wake it up. */
f249412c 1768 }
bdc44640 1769 }
f249412c 1770 return prev;
f1aa6320 1771}
f9480ffc 1772#endif /* !CONFIG_USER_ONLY */
f1aa6320 1773
d9bea114 1774void helper_fork(target_ulong arg1, target_ulong arg2)
f1aa6320 1775{
d9bea114 1776 // arg1 = rt, arg2 = rs
f1aa6320
TS
1777 // TODO: store to TC register
1778}
1779
895c2d04 1780target_ulong helper_yield(CPUMIPSState *env, target_ulong arg)
f1aa6320 1781{
1c7242da
BS
1782 target_long arg1 = arg;
1783
d9bea114 1784 if (arg1 < 0) {
f1aa6320 1785 /* No scheduling policy implemented. */
d9bea114 1786 if (arg1 != -2) {
f1aa6320 1787 if (env->CP0_VPEControl & (1 << CP0VPECo_YSI) &&
b5dc7732 1788 env->active_tc.CP0_TCStatus & (1 << CP0TCSt_DT)) {
f1aa6320
TS
1789 env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
1790 env->CP0_VPEControl |= 4 << CP0VPECo_EXCPT;
895c2d04 1791 helper_raise_exception(env, EXCP_THREAD);
f1aa6320
TS
1792 }
1793 }
d9bea114 1794 } else if (arg1 == 0) {
6958549d 1795 if (0 /* TODO: TC underflow */) {
f1aa6320 1796 env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
895c2d04 1797 helper_raise_exception(env, EXCP_THREAD);
f1aa6320
TS
1798 } else {
1799 // TODO: Deallocate TC
1800 }
d9bea114 1801 } else if (arg1 > 0) {
f1aa6320
TS
1802 /* Yield qualifier inputs not implemented. */
1803 env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
1804 env->CP0_VPEControl |= 2 << CP0VPECo_EXCPT;
895c2d04 1805 helper_raise_exception(env, EXCP_THREAD);
f1aa6320 1806 }
be24bb4f 1807 return env->CP0_YQMask;
f1aa6320
TS
1808}
1809
f1aa6320 1810#ifndef CONFIG_USER_ONLY
6af0bf9c 1811/* TLB management */
7db13fae 1812static void cpu_mips_tlb_flush (CPUMIPSState *env, int flush_global)
814b9a47 1813{
00c8cb0a
AF
1814 MIPSCPU *cpu = mips_env_get_cpu(env);
1815
814b9a47 1816 /* Flush qemu's TLB and discard all shadowed entries. */
00c8cb0a 1817 tlb_flush(CPU(cpu), flush_global);
ead9360e 1818 env->tlb->tlb_in_use = env->tlb->nb_tlb;
814b9a47
TS
1819}
1820
7db13fae 1821static void r4k_mips_tlb_flush_extra (CPUMIPSState *env, int first)
814b9a47
TS
1822{
1823 /* Discard entries from env->tlb[first] onwards. */
ead9360e
TS
1824 while (env->tlb->tlb_in_use > first) {
1825 r4k_invalidate_tlb(env, --env->tlb->tlb_in_use, 0);
814b9a47
TS
1826 }
1827}
1828
895c2d04 1829static void r4k_fill_tlb(CPUMIPSState *env, int idx)
6af0bf9c 1830{
c227f099 1831 r4k_tlb_t *tlb;
6af0bf9c
FB
1832
1833 /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */
ead9360e 1834 tlb = &env->tlb->mmu.r4k.tlb[idx];
9456c2fb
LA
1835 if (env->CP0_EntryHi & (1 << CP0EnHi_EHINV)) {
1836 tlb->EHINV = 1;
1837 return;
1838 }
1839 tlb->EHINV = 0;
f2e9ebef 1840 tlb->VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1);
d26bc211 1841#if defined(TARGET_MIPS64)
e034e2c3 1842 tlb->VPN &= env->SEGMask;
100ce988 1843#endif
98c1b82b 1844 tlb->ASID = env->CP0_EntryHi & 0xFF;
3b1c8be4 1845 tlb->PageMask = env->CP0_PageMask;
6af0bf9c 1846 tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
98c1b82b
PB
1847 tlb->V0 = (env->CP0_EntryLo0 & 2) != 0;
1848 tlb->D0 = (env->CP0_EntryLo0 & 4) != 0;
1849 tlb->C0 = (env->CP0_EntryLo0 >> 3) & 0x7;
2fb58b73
LA
1850 tlb->XI0 = (env->CP0_EntryLo0 >> CP0EnLo_XI) & 1;
1851 tlb->RI0 = (env->CP0_EntryLo0 >> CP0EnLo_RI) & 1;
6af0bf9c 1852 tlb->PFN[0] = (env->CP0_EntryLo0 >> 6) << 12;
98c1b82b
PB
1853 tlb->V1 = (env->CP0_EntryLo1 & 2) != 0;
1854 tlb->D1 = (env->CP0_EntryLo1 & 4) != 0;
1855 tlb->C1 = (env->CP0_EntryLo1 >> 3) & 0x7;
2fb58b73
LA
1856 tlb->XI1 = (env->CP0_EntryLo1 >> CP0EnLo_XI) & 1;
1857 tlb->RI1 = (env->CP0_EntryLo1 >> CP0EnLo_RI) & 1;
6af0bf9c
FB
1858 tlb->PFN[1] = (env->CP0_EntryLo1 >> 6) << 12;
1859}
1860
9456c2fb
LA
1861void r4k_helper_tlbinv(CPUMIPSState *env)
1862{
1863 int idx;
1864 r4k_tlb_t *tlb;
1865 uint8_t ASID = env->CP0_EntryHi & 0xFF;
1866
1867 for (idx = 0; idx < env->tlb->nb_tlb; idx++) {
1868 tlb = &env->tlb->mmu.r4k.tlb[idx];
1869 if (!tlb->G && tlb->ASID == ASID) {
1870 tlb->EHINV = 1;
1871 }
1872 }
1873 cpu_mips_tlb_flush(env, 1);
1874}
1875
1876void r4k_helper_tlbinvf(CPUMIPSState *env)
1877{
1878 int idx;
1879
1880 for (idx = 0; idx < env->tlb->nb_tlb; idx++) {
1881 env->tlb->mmu.r4k.tlb[idx].EHINV = 1;
1882 }
1883 cpu_mips_tlb_flush(env, 1);
1884}
1885
895c2d04 1886void r4k_helper_tlbwi(CPUMIPSState *env)
6af0bf9c 1887{
286d52eb 1888 r4k_tlb_t *tlb;
bbc0d79c 1889 int idx;
286d52eb
AJ
1890 target_ulong VPN;
1891 uint8_t ASID;
1892 bool G, V0, D0, V1, D1;
bbc0d79c
AJ
1893
1894 idx = (env->CP0_Index & ~0x80000000) % env->tlb->nb_tlb;
286d52eb
AJ
1895 tlb = &env->tlb->mmu.r4k.tlb[idx];
1896 VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1);
1897#if defined(TARGET_MIPS64)
1898 VPN &= env->SEGMask;
1899#endif
1900 ASID = env->CP0_EntryHi & 0xff;
1901 G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
1902 V0 = (env->CP0_EntryLo0 & 2) != 0;
1903 D0 = (env->CP0_EntryLo0 & 4) != 0;
1904 V1 = (env->CP0_EntryLo1 & 2) != 0;
1905 D1 = (env->CP0_EntryLo1 & 4) != 0;
1906
1907 /* Discard cached TLB entries, unless tlbwi is just upgrading access
1908 permissions on the current entry. */
1909 if (tlb->VPN != VPN || tlb->ASID != ASID || tlb->G != G ||
1910 (tlb->V0 && !V0) || (tlb->D0 && !D0) ||
1911 (tlb->V1 && !V1) || (tlb->D1 && !D1)) {
1912 r4k_mips_tlb_flush_extra(env, env->tlb->nb_tlb);
1913 }
814b9a47 1914
bbc0d79c 1915 r4k_invalidate_tlb(env, idx, 0);
895c2d04 1916 r4k_fill_tlb(env, idx);
6af0bf9c
FB
1917}
1918
895c2d04 1919void r4k_helper_tlbwr(CPUMIPSState *env)
6af0bf9c
FB
1920{
1921 int r = cpu_mips_get_random(env);
1922
29929e34 1923 r4k_invalidate_tlb(env, r, 1);
895c2d04 1924 r4k_fill_tlb(env, r);
6af0bf9c
FB
1925}
1926
895c2d04 1927void r4k_helper_tlbp(CPUMIPSState *env)
6af0bf9c 1928{
c227f099 1929 r4k_tlb_t *tlb;
f2e9ebef 1930 target_ulong mask;
6af0bf9c 1931 target_ulong tag;
f2e9ebef 1932 target_ulong VPN;
6af0bf9c
FB
1933 uint8_t ASID;
1934 int i;
1935
3d9fb9fe 1936 ASID = env->CP0_EntryHi & 0xFF;
ead9360e
TS
1937 for (i = 0; i < env->tlb->nb_tlb; i++) {
1938 tlb = &env->tlb->mmu.r4k.tlb[i];
f2e9ebef
TS
1939 /* 1k pages are not supported. */
1940 mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
1941 tag = env->CP0_EntryHi & ~mask;
1942 VPN = tlb->VPN & ~mask;
bc3e45e1
AJ
1943#if defined(TARGET_MIPS64)
1944 tag &= env->SEGMask;
1945#endif
6af0bf9c 1946 /* Check ASID, virtual page number & size */
9456c2fb 1947 if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag && !tlb->EHINV) {
6af0bf9c 1948 /* TLB match */
9c2149c8 1949 env->CP0_Index = i;
6af0bf9c
FB
1950 break;
1951 }
1952 }
ead9360e 1953 if (i == env->tlb->nb_tlb) {
814b9a47 1954 /* No match. Discard any shadow entries, if any of them match. */
ead9360e 1955 for (i = env->tlb->nb_tlb; i < env->tlb->tlb_in_use; i++) {
6958549d
AJ
1956 tlb = &env->tlb->mmu.r4k.tlb[i];
1957 /* 1k pages are not supported. */
1958 mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
1959 tag = env->CP0_EntryHi & ~mask;
1960 VPN = tlb->VPN & ~mask;
bc3e45e1
AJ
1961#if defined(TARGET_MIPS64)
1962 tag &= env->SEGMask;
1963#endif
6958549d
AJ
1964 /* Check ASID, virtual page number & size */
1965 if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
29929e34 1966 r4k_mips_tlb_flush_extra (env, i);
6958549d
AJ
1967 break;
1968 }
1969 }
814b9a47 1970
9c2149c8 1971 env->CP0_Index |= 0x80000000;
6af0bf9c
FB
1972 }
1973}
1974
895c2d04 1975void r4k_helper_tlbr(CPUMIPSState *env)
6af0bf9c 1976{
c227f099 1977 r4k_tlb_t *tlb;
09c56b84 1978 uint8_t ASID;
bbc0d79c 1979 int idx;
6af0bf9c 1980
09c56b84 1981 ASID = env->CP0_EntryHi & 0xFF;
bbc0d79c
AJ
1982 idx = (env->CP0_Index & ~0x80000000) % env->tlb->nb_tlb;
1983 tlb = &env->tlb->mmu.r4k.tlb[idx];
4ad40f36
FB
1984
1985 /* If this will change the current ASID, flush qemu's TLB. */
814b9a47
TS
1986 if (ASID != tlb->ASID)
1987 cpu_mips_tlb_flush (env, 1);
1988
ead9360e 1989 r4k_mips_tlb_flush_extra(env, env->tlb->nb_tlb);
4ad40f36 1990
9456c2fb
LA
1991 if (tlb->EHINV) {
1992 env->CP0_EntryHi = 1 << CP0EnHi_EHINV;
1993 env->CP0_PageMask = 0;
1994 env->CP0_EntryLo0 = 0;
1995 env->CP0_EntryLo1 = 0;
1996 } else {
1997 env->CP0_EntryHi = tlb->VPN | tlb->ASID;
1998 env->CP0_PageMask = tlb->PageMask;
1999 env->CP0_EntryLo0 = tlb->G | (tlb->V0 << 1) | (tlb->D0 << 2) |
2fb58b73
LA
2000 ((target_ulong)tlb->RI0 << CP0EnLo_RI) |
2001 ((target_ulong)tlb->XI0 << CP0EnLo_XI) |
7495fd0f 2002 (tlb->C0 << 3) | (tlb->PFN[0] >> 6);
9456c2fb 2003 env->CP0_EntryLo1 = tlb->G | (tlb->V1 << 1) | (tlb->D1 << 2) |
2fb58b73
LA
2004 ((target_ulong)tlb->RI1 << CP0EnLo_RI) |
2005 ((target_ulong)tlb->XI1 << CP0EnLo_XI) |
7495fd0f 2006 (tlb->C1 << 3) | (tlb->PFN[1] >> 6);
9456c2fb 2007 }
6af0bf9c 2008}
6af0bf9c 2009
895c2d04 2010void helper_tlbwi(CPUMIPSState *env)
a7812ae4 2011{
895c2d04 2012 env->tlb->helper_tlbwi(env);
a7812ae4
PB
2013}
2014
895c2d04 2015void helper_tlbwr(CPUMIPSState *env)
a7812ae4 2016{
895c2d04 2017 env->tlb->helper_tlbwr(env);
a7812ae4
PB
2018}
2019
895c2d04 2020void helper_tlbp(CPUMIPSState *env)
a7812ae4 2021{
895c2d04 2022 env->tlb->helper_tlbp(env);
a7812ae4
PB
2023}
2024
895c2d04 2025void helper_tlbr(CPUMIPSState *env)
a7812ae4 2026{
895c2d04 2027 env->tlb->helper_tlbr(env);
a7812ae4
PB
2028}
2029
9456c2fb
LA
2030void helper_tlbinv(CPUMIPSState *env)
2031{
2032 env->tlb->helper_tlbinv(env);
2033}
2034
2035void helper_tlbinvf(CPUMIPSState *env)
2036{
2037 env->tlb->helper_tlbinvf(env);
2038}
2039
2b0233ab 2040/* Specials */
895c2d04 2041target_ulong helper_di(CPUMIPSState *env)
2b0233ab 2042{
2796188e
TS
2043 target_ulong t0 = env->CP0_Status;
2044
be24bb4f 2045 env->CP0_Status = t0 & ~(1 << CP0St_IE);
be24bb4f 2046 return t0;
2b0233ab
TS
2047}
2048
895c2d04 2049target_ulong helper_ei(CPUMIPSState *env)
2b0233ab 2050{
2796188e
TS
2051 target_ulong t0 = env->CP0_Status;
2052
be24bb4f 2053 env->CP0_Status = t0 | (1 << CP0St_IE);
be24bb4f 2054 return t0;
2b0233ab
TS
2055}
2056
895c2d04 2057static void debug_pre_eret(CPUMIPSState *env)
6af0bf9c 2058{
8fec2b8c 2059 if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
93fcfe39
AL
2060 qemu_log("ERET: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
2061 env->active_tc.PC, env->CP0_EPC);
2062 if (env->CP0_Status & (1 << CP0St_ERL))
2063 qemu_log(" ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
2064 if (env->hflags & MIPS_HFLAG_DM)
2065 qemu_log(" DEPC " TARGET_FMT_lx, env->CP0_DEPC);
2066 qemu_log("\n");
2067 }
f41c52f1
TS
2068}
2069
895c2d04 2070static void debug_post_eret(CPUMIPSState *env)
f41c52f1 2071{
a47dddd7
AF
2072 MIPSCPU *cpu = mips_env_get_cpu(env);
2073
8fec2b8c 2074 if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
93fcfe39
AL
2075 qemu_log(" => PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
2076 env->active_tc.PC, env->CP0_EPC);
2077 if (env->CP0_Status & (1 << CP0St_ERL))
2078 qemu_log(" ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
2079 if (env->hflags & MIPS_HFLAG_DM)
2080 qemu_log(" DEPC " TARGET_FMT_lx, env->CP0_DEPC);
2081 switch (env->hflags & MIPS_HFLAG_KSU) {
2082 case MIPS_HFLAG_UM: qemu_log(", UM\n"); break;
2083 case MIPS_HFLAG_SM: qemu_log(", SM\n"); break;
2084 case MIPS_HFLAG_KM: qemu_log("\n"); break;
a47dddd7
AF
2085 default:
2086 cpu_abort(CPU(cpu), "Invalid MMU mode!\n");
2087 break;
93fcfe39 2088 }
623a930e 2089 }
6af0bf9c
FB
2090}
2091
895c2d04 2092static void set_pc(CPUMIPSState *env, target_ulong error_pc)
32188a03
NF
2093{
2094 env->active_tc.PC = error_pc & ~(target_ulong)1;
2095 if (error_pc & 1) {
2096 env->hflags |= MIPS_HFLAG_M16;
2097 } else {
2098 env->hflags &= ~(MIPS_HFLAG_M16);
2099 }
2100}
2101
ce9782f4 2102static inline void exception_return(CPUMIPSState *env)
2b0233ab 2103{
895c2d04 2104 debug_pre_eret(env);
2b0233ab 2105 if (env->CP0_Status & (1 << CP0St_ERL)) {
895c2d04 2106 set_pc(env, env->CP0_ErrorEPC);
2b0233ab
TS
2107 env->CP0_Status &= ~(1 << CP0St_ERL);
2108 } else {
895c2d04 2109 set_pc(env, env->CP0_EPC);
2b0233ab
TS
2110 env->CP0_Status &= ~(1 << CP0St_EXL);
2111 }
2112 compute_hflags(env);
895c2d04 2113 debug_post_eret(env);
ce9782f4
LA
2114}
2115
2116void helper_eret(CPUMIPSState *env)
2117{
2118 exception_return(env);
5499b6ff 2119 env->lladdr = 1;
2b0233ab
TS
2120}
2121
ce9782f4
LA
2122void helper_eretnc(CPUMIPSState *env)
2123{
2124 exception_return(env);
2125}
2126
895c2d04 2127void helper_deret(CPUMIPSState *env)
2b0233ab 2128{
895c2d04
BS
2129 debug_pre_eret(env);
2130 set_pc(env, env->CP0_DEPC);
32188a03 2131
2b0233ab
TS
2132 env->hflags &= MIPS_HFLAG_DM;
2133 compute_hflags(env);
895c2d04 2134 debug_post_eret(env);
5499b6ff 2135 env->lladdr = 1;
2b0233ab 2136}
0eaef5aa 2137#endif /* !CONFIG_USER_ONLY */
2b0233ab 2138
895c2d04 2139target_ulong helper_rdhwr_cpunum(CPUMIPSState *env)
2b0233ab
TS
2140{
2141 if ((env->hflags & MIPS_HFLAG_CP0) ||
2142 (env->CP0_HWREna & (1 << 0)))
2796188e 2143 return env->CP0_EBase & 0x3ff;
2b0233ab 2144 else
895c2d04 2145 helper_raise_exception(env, EXCP_RI);
be24bb4f 2146
2796188e 2147 return 0;
2b0233ab
TS
2148}
2149
895c2d04 2150target_ulong helper_rdhwr_synci_step(CPUMIPSState *env)
2b0233ab
TS
2151{
2152 if ((env->hflags & MIPS_HFLAG_CP0) ||
2153 (env->CP0_HWREna & (1 << 1)))
2796188e 2154 return env->SYNCI_Step;
2b0233ab 2155 else
895c2d04 2156 helper_raise_exception(env, EXCP_RI);
be24bb4f 2157
2796188e 2158 return 0;
2b0233ab
TS
2159}
2160
895c2d04 2161target_ulong helper_rdhwr_cc(CPUMIPSState *env)
2b0233ab
TS
2162{
2163 if ((env->hflags & MIPS_HFLAG_CP0) ||
2164 (env->CP0_HWREna & (1 << 2)))
2796188e 2165 return env->CP0_Count;
2b0233ab 2166 else
895c2d04 2167 helper_raise_exception(env, EXCP_RI);
be24bb4f 2168
2796188e 2169 return 0;
2b0233ab
TS
2170}
2171
895c2d04 2172target_ulong helper_rdhwr_ccres(CPUMIPSState *env)
2b0233ab
TS
2173{
2174 if ((env->hflags & MIPS_HFLAG_CP0) ||
2175 (env->CP0_HWREna & (1 << 3)))
2796188e 2176 return env->CCRes;
2b0233ab 2177 else
895c2d04 2178 helper_raise_exception(env, EXCP_RI);
be24bb4f 2179
2796188e 2180 return 0;
2b0233ab
TS
2181}
2182
895c2d04 2183void helper_pmon(CPUMIPSState *env, int function)
6af0bf9c
FB
2184{
2185 function /= 2;
2186 switch (function) {
2187 case 2: /* TODO: char inbyte(int waitflag); */
b5dc7732
TS
2188 if (env->active_tc.gpr[4] == 0)
2189 env->active_tc.gpr[2] = -1;
6af0bf9c
FB
2190 /* Fall through */
2191 case 11: /* TODO: char inbyte (void); */
b5dc7732 2192 env->active_tc.gpr[2] = -1;
6af0bf9c
FB
2193 break;
2194 case 3:
2195 case 12:
b5dc7732 2196 printf("%c", (char)(env->active_tc.gpr[4] & 0xFF));
6af0bf9c
FB
2197 break;
2198 case 17:
2199 break;
2200 case 158:
2201 {
b69e48a8 2202 unsigned char *fmt = (void *)(uintptr_t)env->active_tc.gpr[4];
6af0bf9c
FB
2203 printf("%s", fmt);
2204 }
2205 break;
2206 }
2207}
e37e863f 2208
895c2d04 2209void helper_wait(CPUMIPSState *env)
08ba7963 2210{
259186a7
AF
2211 CPUState *cs = CPU(mips_env_get_cpu(env));
2212
2213 cs->halted = 1;
d8ed887b 2214 cpu_reset_interrupt(cs, CPU_INTERRUPT_WAKE);
895c2d04 2215 helper_raise_exception(env, EXCP_HLT);
08ba7963
TS
2216}
2217
5fafdf24 2218#if !defined(CONFIG_USER_ONLY)
e37e863f 2219
93e22326 2220void mips_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
aea14095
LA
2221 int access_type, int is_user,
2222 uintptr_t retaddr)
4ad40f36 2223{
93e22326
PB
2224 MIPSCPU *cpu = MIPS_CPU(cs);
2225 CPUMIPSState *env = &cpu->env;
aea14095
LA
2226 int error_code = 0;
2227 int excp;
93e22326 2228
4ad40f36 2229 env->CP0_BadVAddr = addr;
aea14095
LA
2230
2231 if (access_type == MMU_DATA_STORE) {
2232 excp = EXCP_AdES;
2233 } else {
2234 excp = EXCP_AdEL;
2235 if (access_type == MMU_INST_FETCH) {
2236 error_code |= EXCP_INST_NOTAVAIL;
2237 }
2238 }
2239
2240 do_raise_exception_err(env, excp, error_code, retaddr);
4ad40f36
FB
2241}
2242
d5a11fef 2243void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx,
20503968 2244 uintptr_t retaddr)
e37e863f 2245{
e37e863f
FB
2246 int ret;
2247
27103424 2248 ret = mips_cpu_handle_mmu_fault(cs, addr, is_write, mmu_idx);
e37e863f 2249 if (ret) {
d5a11fef
AF
2250 MIPSCPU *cpu = MIPS_CPU(cs);
2251 CPUMIPSState *env = &cpu->env;
2252
27103424 2253 do_raise_exception_err(env, cs->exception_index,
5f7319cd 2254 env->error_code, retaddr);
e37e863f 2255 }
e37e863f
FB
2256}
2257
c658b94f
AF
2258void mips_cpu_unassigned_access(CPUState *cs, hwaddr addr,
2259 bool is_write, bool is_exec, int unused,
2260 unsigned size)
647de6ca 2261{
c658b94f
AF
2262 MIPSCPU *cpu = MIPS_CPU(cs);
2263 CPUMIPSState *env = &cpu->env;
2264
eddedd54
JH
2265 /*
2266 * Raising an exception with KVM enabled will crash because it won't be from
2267 * the main execution loop so the longjmp won't have a matching setjmp.
2268 * Until we can trigger a bus error exception through KVM lets just ignore
2269 * the access.
2270 */
2271 if (kvm_enabled()) {
2272 return;
2273 }
2274
c658b94f 2275 if (is_exec) {
895c2d04 2276 helper_raise_exception(env, EXCP_IBE);
c658b94f 2277 } else {
895c2d04 2278 helper_raise_exception(env, EXCP_DBE);
c658b94f 2279 }
647de6ca 2280}
f1aa6320 2281#endif /* !CONFIG_USER_ONLY */
fd4a04eb
TS
2282
2283/* Complex FPU operations which may need stack space. */
2284
f090c9d4
PB
2285#define FLOAT_TWO32 make_float32(1 << 30)
2286#define FLOAT_TWO64 make_float64(1ULL << 62)
05993cd0
AJ
2287#define FP_TO_INT32_OVERFLOW 0x7fffffff
2288#define FP_TO_INT64_OVERFLOW 0x7fffffffffffffffULL
8dfdb87c 2289
fd4a04eb 2290/* convert MIPS rounding mode in FCR31 to IEEE library */
b7651e95 2291unsigned int ieee_rm[] = {
fd4a04eb
TS
2292 float_round_nearest_even,
2293 float_round_to_zero,
2294 float_round_up,
2295 float_round_down
2296};
2297
895c2d04 2298target_ulong helper_cfc1(CPUMIPSState *env, uint32_t reg)
fd4a04eb 2299{
736d120a 2300 target_ulong arg1 = 0;
6c5c1e20 2301
ead9360e
TS
2302 switch (reg) {
2303 case 0:
d9bea114 2304 arg1 = (int32_t)env->active_fpu.fcr0;
ead9360e 2305 break;
736d120a
PJ
2306 case 1:
2307 /* UFR Support - Read Status FR */
2308 if (env->active_fpu.fcr0 & (1 << FCR0_UFRP)) {
2309 if (env->CP0_Config5 & (1 << CP0C5_UFR)) {
2310 arg1 = (int32_t)
2311 ((env->CP0_Status & (1 << CP0St_FR)) >> CP0St_FR);
2312 } else {
2313 helper_raise_exception(env, EXCP_RI);
2314 }
2315 }
2316 break;
7c979afd
LA
2317 case 5:
2318 /* FRE Support - read Config5.FRE bit */
2319 if (env->active_fpu.fcr0 & (1 << FCR0_FREP)) {
2320 if (env->CP0_Config5 & (1 << CP0C5_UFE)) {
2321 arg1 = (env->CP0_Config5 >> CP0C5_FRE) & 1;
2322 } else {
2323 helper_raise_exception(env, EXCP_RI);
2324 }
2325 }
2326 break;
ead9360e 2327 case 25:
d9bea114 2328 arg1 = ((env->active_fpu.fcr31 >> 24) & 0xfe) | ((env->active_fpu.fcr31 >> 23) & 0x1);
ead9360e
TS
2329 break;
2330 case 26:
d9bea114 2331 arg1 = env->active_fpu.fcr31 & 0x0003f07c;
ead9360e
TS
2332 break;
2333 case 28:
d9bea114 2334 arg1 = (env->active_fpu.fcr31 & 0x00000f83) | ((env->active_fpu.fcr31 >> 22) & 0x4);
ead9360e
TS
2335 break;
2336 default:
d9bea114 2337 arg1 = (int32_t)env->active_fpu.fcr31;
ead9360e
TS
2338 break;
2339 }
be24bb4f 2340
d9bea114 2341 return arg1;
ead9360e
TS
2342}
2343
736d120a 2344void helper_ctc1(CPUMIPSState *env, target_ulong arg1, uint32_t fs, uint32_t rt)
ead9360e 2345{
736d120a
PJ
2346 switch (fs) {
2347 case 1:
2348 /* UFR Alias - Reset Status FR */
2349 if (!((env->active_fpu.fcr0 & (1 << FCR0_UFRP)) && (rt == 0))) {
2350 return;
2351 }
2352 if (env->CP0_Config5 & (1 << CP0C5_UFR)) {
2353 env->CP0_Status &= ~(1 << CP0St_FR);
2354 compute_hflags(env);
2355 } else {
2356 helper_raise_exception(env, EXCP_RI);
2357 }
2358 break;
2359 case 4:
2360 /* UNFR Alias - Set Status FR */
2361 if (!((env->active_fpu.fcr0 & (1 << FCR0_UFRP)) && (rt == 0))) {
2362 return;
2363 }
2364 if (env->CP0_Config5 & (1 << CP0C5_UFR)) {
2365 env->CP0_Status |= (1 << CP0St_FR);
2366 compute_hflags(env);
2367 } else {
2368 helper_raise_exception(env, EXCP_RI);
2369 }
2370 break;
7c979afd
LA
2371 case 5:
2372 /* FRE Support - clear Config5.FRE bit */
2373 if (!((env->active_fpu.fcr0 & (1 << FCR0_FREP)) && (rt == 0))) {
2374 return;
2375 }
2376 if (env->CP0_Config5 & (1 << CP0C5_UFE)) {
2377 env->CP0_Config5 &= ~(1 << CP0C5_FRE);
2378 compute_hflags(env);
2379 } else {
2380 helper_raise_exception(env, EXCP_RI);
2381 }
2382 break;
2383 case 6:
2384 /* FRE Support - set Config5.FRE bit */
2385 if (!((env->active_fpu.fcr0 & (1 << FCR0_FREP)) && (rt == 0))) {
2386 return;
2387 }
2388 if (env->CP0_Config5 & (1 << CP0C5_UFE)) {
2389 env->CP0_Config5 |= (1 << CP0C5_FRE);
2390 compute_hflags(env);
2391 } else {
2392 helper_raise_exception(env, EXCP_RI);
2393 }
2394 break;
fd4a04eb 2395 case 25:
ba801af4 2396 if ((env->insn_flags & ISA_MIPS32R6) || (arg1 & 0xffffff00)) {
fd4a04eb 2397 return;
ba801af4 2398 }
d9bea114
AJ
2399 env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0x017fffff) | ((arg1 & 0xfe) << 24) |
2400 ((arg1 & 0x1) << 23);
fd4a04eb
TS
2401 break;
2402 case 26:
d9bea114 2403 if (arg1 & 0x007c0000)
fd4a04eb 2404 return;
d9bea114 2405 env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0xfffc0f83) | (arg1 & 0x0003f07c);
fd4a04eb
TS
2406 break;
2407 case 28:
d9bea114 2408 if (arg1 & 0x007c0000)
fd4a04eb 2409 return;
d9bea114
AJ
2410 env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0xfefff07c) | (arg1 & 0x00000f83) |
2411 ((arg1 & 0x4) << 22);
fd4a04eb
TS
2412 break;
2413 case 31:
ba801af4
LA
2414 if (env->insn_flags & ISA_MIPS32R6) {
2415 uint32_t mask = 0xfefc0000;
2416 env->active_fpu.fcr31 = (arg1 & ~mask) |
2417 (env->active_fpu.fcr31 & mask);
2418 } else if (!(arg1 & 0x007c0000)) {
2419 env->active_fpu.fcr31 = arg1;
2420 }
fd4a04eb
TS
2421 break;
2422 default:
2423 return;
2424 }
2425 /* set rounding mode */
e320d05a 2426 restore_rounding_mode(env);
41e0c701 2427 /* set flush-to-zero mode */
e320d05a 2428 restore_flush_mode(env);
f01be154
TS
2429 set_float_exception_flags(0, &env->active_fpu.fp_status);
2430 if ((GET_FP_ENABLE(env->active_fpu.fcr31) | 0x20) & GET_FP_CAUSE(env->active_fpu.fcr31))
5f7319cd 2431 do_raise_exception(env, EXCP_FPE, GETPC());
fd4a04eb
TS
2432}
2433
b7651e95 2434int ieee_ex_to_mips(int xcpt)
fd4a04eb 2435{
353ebb7a
AJ
2436 int ret = 0;
2437 if (xcpt) {
2438 if (xcpt & float_flag_invalid) {
2439 ret |= FP_INVALID;
2440 }
2441 if (xcpt & float_flag_overflow) {
2442 ret |= FP_OVERFLOW;
2443 }
2444 if (xcpt & float_flag_underflow) {
2445 ret |= FP_UNDERFLOW;
2446 }
2447 if (xcpt & float_flag_divbyzero) {
2448 ret |= FP_DIV0;
2449 }
2450 if (xcpt & float_flag_inexact) {
2451 ret |= FP_INEXACT;
2452 }
2453 }
2454 return ret;
fd4a04eb
TS
2455}
2456
5f7319cd 2457static inline void update_fcr31(CPUMIPSState *env, uintptr_t pc)
fd4a04eb 2458{
f01be154 2459 int tmp = ieee_ex_to_mips(get_float_exception_flags(&env->active_fpu.fp_status));
fd4a04eb 2460
f01be154 2461 SET_FP_CAUSE(env->active_fpu.fcr31, tmp);
4a587b2c
AJ
2462
2463 if (tmp) {
2464 set_float_exception_flags(0, &env->active_fpu.fp_status);
2465
2466 if (GET_FP_ENABLE(env->active_fpu.fcr31) & tmp) {
5f7319cd 2467 do_raise_exception(env, EXCP_FPE, pc);
4a587b2c
AJ
2468 } else {
2469 UPDATE_FP_FLAGS(env->active_fpu.fcr31, tmp);
2470 }
2471 }
fd4a04eb
TS
2472}
2473
a16336e4
TS
2474/* Float support.
2475 Single precition routines have a "s" suffix, double precision a
2476 "d" suffix, 32bit integer "w", 64bit integer "l", paired single "ps",
2477 paired single lower "pl", paired single upper "pu". */
2478
a16336e4 2479/* unary operations, modifying fp status */
895c2d04 2480uint64_t helper_float_sqrt_d(CPUMIPSState *env, uint64_t fdt0)
b6d96bed 2481{
5dbe90bb 2482 fdt0 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
5f7319cd 2483 update_fcr31(env, GETPC());
5dbe90bb 2484 return fdt0;
b6d96bed
TS
2485}
2486
895c2d04 2487uint32_t helper_float_sqrt_s(CPUMIPSState *env, uint32_t fst0)
b6d96bed 2488{
5dbe90bb 2489 fst0 = float32_sqrt(fst0, &env->active_fpu.fp_status);
5f7319cd 2490 update_fcr31(env, GETPC());
5dbe90bb 2491 return fst0;
b6d96bed 2492}
a16336e4 2493
895c2d04 2494uint64_t helper_float_cvtd_s(CPUMIPSState *env, uint32_t fst0)
fd4a04eb 2495{
b6d96bed
TS
2496 uint64_t fdt2;
2497
f01be154 2498 fdt2 = float32_to_float64(fst0, &env->active_fpu.fp_status);
5f7319cd 2499 update_fcr31(env, GETPC());
b6d96bed 2500 return fdt2;
fd4a04eb 2501}
b6d96bed 2502
895c2d04 2503uint64_t helper_float_cvtd_w(CPUMIPSState *env, uint32_t wt0)
fd4a04eb 2504{
b6d96bed
TS
2505 uint64_t fdt2;
2506
f01be154 2507 fdt2 = int32_to_float64(wt0, &env->active_fpu.fp_status);
5f7319cd 2508 update_fcr31(env, GETPC());
b6d96bed 2509 return fdt2;
fd4a04eb 2510}
b6d96bed 2511
895c2d04 2512uint64_t helper_float_cvtd_l(CPUMIPSState *env, uint64_t dt0)
fd4a04eb 2513{
b6d96bed
TS
2514 uint64_t fdt2;
2515
f01be154 2516 fdt2 = int64_to_float64(dt0, &env->active_fpu.fp_status);
5f7319cd 2517 update_fcr31(env, GETPC());
b6d96bed 2518 return fdt2;
fd4a04eb 2519}
b6d96bed 2520
895c2d04 2521uint64_t helper_float_cvtl_d(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 2522{
b6d96bed
TS
2523 uint64_t dt2;
2524
f01be154 2525 dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
4cc2e5f9
AJ
2526 if (get_float_exception_flags(&env->active_fpu.fp_status)
2527 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2528 dt2 = FP_TO_INT64_OVERFLOW;
4cc2e5f9 2529 }
5f7319cd 2530 update_fcr31(env, GETPC());
b6d96bed 2531 return dt2;
fd4a04eb 2532}
b6d96bed 2533
895c2d04 2534uint64_t helper_float_cvtl_s(CPUMIPSState *env, uint32_t fst0)
fd4a04eb 2535{
b6d96bed
TS
2536 uint64_t dt2;
2537
f01be154 2538 dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
4cc2e5f9
AJ
2539 if (get_float_exception_flags(&env->active_fpu.fp_status)
2540 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2541 dt2 = FP_TO_INT64_OVERFLOW;
4cc2e5f9 2542 }
5f7319cd 2543 update_fcr31(env, GETPC());
b6d96bed 2544 return dt2;
fd4a04eb
TS
2545}
2546
895c2d04 2547uint64_t helper_float_cvtps_pw(CPUMIPSState *env, uint64_t dt0)
fd4a04eb 2548{
b6d96bed
TS
2549 uint32_t fst2;
2550 uint32_t fsth2;
2551
f01be154
TS
2552 fst2 = int32_to_float32(dt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
2553 fsth2 = int32_to_float32(dt0 >> 32, &env->active_fpu.fp_status);
5f7319cd 2554 update_fcr31(env, GETPC());
b6d96bed 2555 return ((uint64_t)fsth2 << 32) | fst2;
fd4a04eb 2556}
b6d96bed 2557
895c2d04 2558uint64_t helper_float_cvtpw_ps(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 2559{
b6d96bed
TS
2560 uint32_t wt2;
2561 uint32_t wth2;
5dbe90bb 2562 int excp, excph;
b6d96bed 2563
f01be154 2564 wt2 = float32_to_int32(fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
5dbe90bb
AJ
2565 excp = get_float_exception_flags(&env->active_fpu.fp_status);
2566 if (excp & (float_flag_overflow | float_flag_invalid)) {
05993cd0 2567 wt2 = FP_TO_INT32_OVERFLOW;
5dbe90bb
AJ
2568 }
2569
2570 set_float_exception_flags(0, &env->active_fpu.fp_status);
2571 wth2 = float32_to_int32(fdt0 >> 32, &env->active_fpu.fp_status);
2572 excph = get_float_exception_flags(&env->active_fpu.fp_status);
2573 if (excph & (float_flag_overflow | float_flag_invalid)) {
05993cd0 2574 wth2 = FP_TO_INT32_OVERFLOW;
b6d96bed 2575 }
5dbe90bb
AJ
2576
2577 set_float_exception_flags(excp | excph, &env->active_fpu.fp_status);
5f7319cd 2578 update_fcr31(env, GETPC());
5dbe90bb 2579
b6d96bed 2580 return ((uint64_t)wth2 << 32) | wt2;
fd4a04eb 2581}
b6d96bed 2582
895c2d04 2583uint32_t helper_float_cvts_d(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 2584{
b6d96bed
TS
2585 uint32_t fst2;
2586
f01be154 2587 fst2 = float64_to_float32(fdt0, &env->active_fpu.fp_status);
5f7319cd 2588 update_fcr31(env, GETPC());
b6d96bed 2589 return fst2;
fd4a04eb 2590}
b6d96bed 2591
895c2d04 2592uint32_t helper_float_cvts_w(CPUMIPSState *env, uint32_t wt0)
fd4a04eb 2593{
b6d96bed
TS
2594 uint32_t fst2;
2595
f01be154 2596 fst2 = int32_to_float32(wt0, &env->active_fpu.fp_status);
5f7319cd 2597 update_fcr31(env, GETPC());
b6d96bed 2598 return fst2;
fd4a04eb 2599}
b6d96bed 2600
895c2d04 2601uint32_t helper_float_cvts_l(CPUMIPSState *env, uint64_t dt0)
fd4a04eb 2602{
b6d96bed
TS
2603 uint32_t fst2;
2604
f01be154 2605 fst2 = int64_to_float32(dt0, &env->active_fpu.fp_status);
5f7319cd 2606 update_fcr31(env, GETPC());
b6d96bed 2607 return fst2;
fd4a04eb 2608}
b6d96bed 2609
895c2d04 2610uint32_t helper_float_cvts_pl(CPUMIPSState *env, uint32_t wt0)
fd4a04eb 2611{
b6d96bed
TS
2612 uint32_t wt2;
2613
b6d96bed 2614 wt2 = wt0;
5f7319cd 2615 update_fcr31(env, GETPC());
b6d96bed 2616 return wt2;
fd4a04eb 2617}
b6d96bed 2618
895c2d04 2619uint32_t helper_float_cvts_pu(CPUMIPSState *env, uint32_t wth0)
fd4a04eb 2620{
b6d96bed
TS
2621 uint32_t wt2;
2622
b6d96bed 2623 wt2 = wth0;
5f7319cd 2624 update_fcr31(env, GETPC());
b6d96bed 2625 return wt2;
fd4a04eb 2626}
b6d96bed 2627
895c2d04 2628uint32_t helper_float_cvtw_s(CPUMIPSState *env, uint32_t fst0)
fd4a04eb 2629{
b6d96bed
TS
2630 uint32_t wt2;
2631
f01be154 2632 wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
4cc2e5f9
AJ
2633 if (get_float_exception_flags(&env->active_fpu.fp_status)
2634 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2635 wt2 = FP_TO_INT32_OVERFLOW;
4cc2e5f9 2636 }
2b09f94c 2637 update_fcr31(env, GETPC());
b6d96bed 2638 return wt2;
fd4a04eb 2639}
b6d96bed 2640
895c2d04 2641uint32_t helper_float_cvtw_d(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 2642{
b6d96bed
TS
2643 uint32_t wt2;
2644
f01be154 2645 wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
4cc2e5f9
AJ
2646 if (get_float_exception_flags(&env->active_fpu.fp_status)
2647 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2648 wt2 = FP_TO_INT32_OVERFLOW;
4cc2e5f9 2649 }
5f7319cd 2650 update_fcr31(env, GETPC());
b6d96bed 2651 return wt2;
fd4a04eb
TS
2652}
2653
895c2d04 2654uint64_t helper_float_roundl_d(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 2655{
b6d96bed
TS
2656 uint64_t dt2;
2657
f01be154
TS
2658 set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2659 dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
e320d05a 2660 restore_rounding_mode(env);
4cc2e5f9
AJ
2661 if (get_float_exception_flags(&env->active_fpu.fp_status)
2662 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2663 dt2 = FP_TO_INT64_OVERFLOW;
4cc2e5f9 2664 }
5f7319cd 2665 update_fcr31(env, GETPC());
b6d96bed 2666 return dt2;
fd4a04eb 2667}
b6d96bed 2668
895c2d04 2669uint64_t helper_float_roundl_s(CPUMIPSState *env, uint32_t fst0)
fd4a04eb 2670{
b6d96bed
TS
2671 uint64_t dt2;
2672
f01be154
TS
2673 set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2674 dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
e320d05a 2675 restore_rounding_mode(env);
4cc2e5f9
AJ
2676 if (get_float_exception_flags(&env->active_fpu.fp_status)
2677 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2678 dt2 = FP_TO_INT64_OVERFLOW;
4cc2e5f9 2679 }
5f7319cd 2680 update_fcr31(env, GETPC());
b6d96bed 2681 return dt2;
fd4a04eb 2682}
b6d96bed 2683
895c2d04 2684uint32_t helper_float_roundw_d(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 2685{
b6d96bed
TS
2686 uint32_t wt2;
2687
f01be154
TS
2688 set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2689 wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
e320d05a 2690 restore_rounding_mode(env);
4cc2e5f9
AJ
2691 if (get_float_exception_flags(&env->active_fpu.fp_status)
2692 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2693 wt2 = FP_TO_INT32_OVERFLOW;
4cc2e5f9 2694 }
5f7319cd 2695 update_fcr31(env, GETPC());
b6d96bed 2696 return wt2;
fd4a04eb 2697}
b6d96bed 2698
895c2d04 2699uint32_t helper_float_roundw_s(CPUMIPSState *env, uint32_t fst0)
fd4a04eb 2700{
b6d96bed
TS
2701 uint32_t wt2;
2702
f01be154
TS
2703 set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2704 wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
e320d05a 2705 restore_rounding_mode(env);
4cc2e5f9
AJ
2706 if (get_float_exception_flags(&env->active_fpu.fp_status)
2707 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2708 wt2 = FP_TO_INT32_OVERFLOW;
4cc2e5f9 2709 }
5f7319cd 2710 update_fcr31(env, GETPC());
b6d96bed 2711 return wt2;
fd4a04eb
TS
2712}
2713
895c2d04 2714uint64_t helper_float_truncl_d(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 2715{
b6d96bed
TS
2716 uint64_t dt2;
2717
f01be154 2718 dt2 = float64_to_int64_round_to_zero(fdt0, &env->active_fpu.fp_status);
4cc2e5f9
AJ
2719 if (get_float_exception_flags(&env->active_fpu.fp_status)
2720 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2721 dt2 = FP_TO_INT64_OVERFLOW;
4cc2e5f9 2722 }
5f7319cd 2723 update_fcr31(env, GETPC());
b6d96bed 2724 return dt2;
fd4a04eb 2725}
b6d96bed 2726
895c2d04 2727uint64_t helper_float_truncl_s(CPUMIPSState *env, uint32_t fst0)
fd4a04eb 2728{
b6d96bed
TS
2729 uint64_t dt2;
2730
f01be154 2731 dt2 = float32_to_int64_round_to_zero(fst0, &env->active_fpu.fp_status);
4cc2e5f9
AJ
2732 if (get_float_exception_flags(&env->active_fpu.fp_status)
2733 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2734 dt2 = FP_TO_INT64_OVERFLOW;
4cc2e5f9 2735 }
5f7319cd 2736 update_fcr31(env, GETPC());
b6d96bed 2737 return dt2;
fd4a04eb 2738}
b6d96bed 2739
895c2d04 2740uint32_t helper_float_truncw_d(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 2741{
b6d96bed
TS
2742 uint32_t wt2;
2743
f01be154 2744 wt2 = float64_to_int32_round_to_zero(fdt0, &env->active_fpu.fp_status);
4cc2e5f9
AJ
2745 if (get_float_exception_flags(&env->active_fpu.fp_status)
2746 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2747 wt2 = FP_TO_INT32_OVERFLOW;
4cc2e5f9 2748 }
5f7319cd 2749 update_fcr31(env, GETPC());
b6d96bed 2750 return wt2;
fd4a04eb 2751}
b6d96bed 2752
895c2d04 2753uint32_t helper_float_truncw_s(CPUMIPSState *env, uint32_t fst0)
fd4a04eb 2754{
b6d96bed
TS
2755 uint32_t wt2;
2756
f01be154 2757 wt2 = float32_to_int32_round_to_zero(fst0, &env->active_fpu.fp_status);
4cc2e5f9
AJ
2758 if (get_float_exception_flags(&env->active_fpu.fp_status)
2759 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2760 wt2 = FP_TO_INT32_OVERFLOW;
4cc2e5f9 2761 }
5f7319cd 2762 update_fcr31(env, GETPC());
b6d96bed 2763 return wt2;
fd4a04eb
TS
2764}
2765
895c2d04 2766uint64_t helper_float_ceill_d(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 2767{
b6d96bed
TS
2768 uint64_t dt2;
2769
f01be154
TS
2770 set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
2771 dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
e320d05a 2772 restore_rounding_mode(env);
4cc2e5f9
AJ
2773 if (get_float_exception_flags(&env->active_fpu.fp_status)
2774 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2775 dt2 = FP_TO_INT64_OVERFLOW;
4cc2e5f9 2776 }
5f7319cd 2777 update_fcr31(env, GETPC());
b6d96bed 2778 return dt2;
fd4a04eb 2779}
b6d96bed 2780
895c2d04 2781uint64_t helper_float_ceill_s(CPUMIPSState *env, uint32_t fst0)
fd4a04eb 2782{
b6d96bed
TS
2783 uint64_t dt2;
2784
f01be154
TS
2785 set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
2786 dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
e320d05a 2787 restore_rounding_mode(env);
4cc2e5f9
AJ
2788 if (get_float_exception_flags(&env->active_fpu.fp_status)
2789 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2790 dt2 = FP_TO_INT64_OVERFLOW;
4cc2e5f9 2791 }
5f7319cd 2792 update_fcr31(env, GETPC());
b6d96bed 2793 return dt2;
fd4a04eb 2794}
b6d96bed 2795
895c2d04 2796uint32_t helper_float_ceilw_d(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 2797{
b6d96bed
TS
2798 uint32_t wt2;
2799
f01be154
TS
2800 set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
2801 wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
e320d05a 2802 restore_rounding_mode(env);
4cc2e5f9
AJ
2803 if (get_float_exception_flags(&env->active_fpu.fp_status)
2804 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2805 wt2 = FP_TO_INT32_OVERFLOW;
4cc2e5f9 2806 }
5f7319cd 2807 update_fcr31(env, GETPC());
b6d96bed 2808 return wt2;
fd4a04eb 2809}
b6d96bed 2810
895c2d04 2811uint32_t helper_float_ceilw_s(CPUMIPSState *env, uint32_t fst0)
fd4a04eb 2812{
b6d96bed
TS
2813 uint32_t wt2;
2814
f01be154
TS
2815 set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
2816 wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
e320d05a 2817 restore_rounding_mode(env);
4cc2e5f9
AJ
2818 if (get_float_exception_flags(&env->active_fpu.fp_status)
2819 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2820 wt2 = FP_TO_INT32_OVERFLOW;
4cc2e5f9 2821 }
5f7319cd 2822 update_fcr31(env, GETPC());
b6d96bed 2823 return wt2;
fd4a04eb
TS
2824}
2825
895c2d04 2826uint64_t helper_float_floorl_d(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 2827{
b6d96bed
TS
2828 uint64_t dt2;
2829
f01be154
TS
2830 set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
2831 dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
e320d05a 2832 restore_rounding_mode(env);
4cc2e5f9
AJ
2833 if (get_float_exception_flags(&env->active_fpu.fp_status)
2834 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2835 dt2 = FP_TO_INT64_OVERFLOW;
4cc2e5f9 2836 }
5f7319cd 2837 update_fcr31(env, GETPC());
b6d96bed 2838 return dt2;
fd4a04eb 2839}
b6d96bed 2840
895c2d04 2841uint64_t helper_float_floorl_s(CPUMIPSState *env, uint32_t fst0)
fd4a04eb 2842{
b6d96bed
TS
2843 uint64_t dt2;
2844
f01be154
TS
2845 set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
2846 dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
e320d05a 2847 restore_rounding_mode(env);
4cc2e5f9
AJ
2848 if (get_float_exception_flags(&env->active_fpu.fp_status)
2849 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2850 dt2 = FP_TO_INT64_OVERFLOW;
4cc2e5f9 2851 }
5f7319cd 2852 update_fcr31(env, GETPC());
b6d96bed 2853 return dt2;
fd4a04eb 2854}
b6d96bed 2855
895c2d04 2856uint32_t helper_float_floorw_d(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 2857{
b6d96bed
TS
2858 uint32_t wt2;
2859
f01be154
TS
2860 set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
2861 wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
e320d05a 2862 restore_rounding_mode(env);
4cc2e5f9
AJ
2863 if (get_float_exception_flags(&env->active_fpu.fp_status)
2864 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2865 wt2 = FP_TO_INT32_OVERFLOW;
4cc2e5f9 2866 }
5f7319cd 2867 update_fcr31(env, GETPC());
b6d96bed 2868 return wt2;
fd4a04eb 2869}
b6d96bed 2870
895c2d04 2871uint32_t helper_float_floorw_s(CPUMIPSState *env, uint32_t fst0)
fd4a04eb 2872{
b6d96bed
TS
2873 uint32_t wt2;
2874
f01be154
TS
2875 set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
2876 wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
e320d05a 2877 restore_rounding_mode(env);
4cc2e5f9
AJ
2878 if (get_float_exception_flags(&env->active_fpu.fp_status)
2879 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2880 wt2 = FP_TO_INT32_OVERFLOW;
4cc2e5f9 2881 }
5f7319cd 2882 update_fcr31(env, GETPC());
b6d96bed 2883 return wt2;
fd4a04eb
TS
2884}
2885
a16336e4 2886/* unary operations, not modifying fp status */
b6d96bed 2887#define FLOAT_UNOP(name) \
c01fccd2 2888uint64_t helper_float_ ## name ## _d(uint64_t fdt0) \
b6d96bed
TS
2889{ \
2890 return float64_ ## name(fdt0); \
2891} \
c01fccd2 2892uint32_t helper_float_ ## name ## _s(uint32_t fst0) \
b6d96bed
TS
2893{ \
2894 return float32_ ## name(fst0); \
2895} \
c01fccd2 2896uint64_t helper_float_ ## name ## _ps(uint64_t fdt0) \
b6d96bed
TS
2897{ \
2898 uint32_t wt0; \
2899 uint32_t wth0; \
2900 \
2901 wt0 = float32_ ## name(fdt0 & 0XFFFFFFFF); \
2902 wth0 = float32_ ## name(fdt0 >> 32); \
2903 return ((uint64_t)wth0 << 32) | wt0; \
a16336e4
TS
2904}
2905FLOAT_UNOP(abs)
2906FLOAT_UNOP(chs)
2907#undef FLOAT_UNOP
2908
8dfdb87c 2909/* MIPS specific unary operations */
895c2d04 2910uint64_t helper_float_recip_d(CPUMIPSState *env, uint64_t fdt0)
8dfdb87c 2911{
b6d96bed
TS
2912 uint64_t fdt2;
2913
05993cd0 2914 fdt2 = float64_div(float64_one, fdt0, &env->active_fpu.fp_status);
5f7319cd 2915 update_fcr31(env, GETPC());
b6d96bed 2916 return fdt2;
8dfdb87c 2917}
b6d96bed 2918
895c2d04 2919uint32_t helper_float_recip_s(CPUMIPSState *env, uint32_t fst0)
8dfdb87c 2920{
b6d96bed
TS
2921 uint32_t fst2;
2922
05993cd0 2923 fst2 = float32_div(float32_one, fst0, &env->active_fpu.fp_status);
5f7319cd 2924 update_fcr31(env, GETPC());
b6d96bed 2925 return fst2;
57fa1fb3 2926}
57fa1fb3 2927
895c2d04 2928uint64_t helper_float_rsqrt_d(CPUMIPSState *env, uint64_t fdt0)
8dfdb87c 2929{
b6d96bed
TS
2930 uint64_t fdt2;
2931
f01be154 2932 fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
05993cd0 2933 fdt2 = float64_div(float64_one, fdt2, &env->active_fpu.fp_status);
5f7319cd 2934 update_fcr31(env, GETPC());
b6d96bed 2935 return fdt2;
8dfdb87c 2936}
b6d96bed 2937
895c2d04 2938uint32_t helper_float_rsqrt_s(CPUMIPSState *env, uint32_t fst0)
8dfdb87c 2939{
b6d96bed
TS
2940 uint32_t fst2;
2941
f01be154 2942 fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status);
05993cd0 2943 fst2 = float32_div(float32_one, fst2, &env->active_fpu.fp_status);
5f7319cd 2944 update_fcr31(env, GETPC());
b6d96bed 2945 return fst2;
8dfdb87c
TS
2946}
2947
895c2d04 2948uint64_t helper_float_recip1_d(CPUMIPSState *env, uint64_t fdt0)
8dfdb87c 2949{
b6d96bed
TS
2950 uint64_t fdt2;
2951
05993cd0 2952 fdt2 = float64_div(float64_one, fdt0, &env->active_fpu.fp_status);
5f7319cd 2953 update_fcr31(env, GETPC());
b6d96bed 2954 return fdt2;
8dfdb87c 2955}
b6d96bed 2956
895c2d04 2957uint32_t helper_float_recip1_s(CPUMIPSState *env, uint32_t fst0)
8dfdb87c 2958{
b6d96bed
TS
2959 uint32_t fst2;
2960
05993cd0 2961 fst2 = float32_div(float32_one, fst0, &env->active_fpu.fp_status);
5f7319cd 2962 update_fcr31(env, GETPC());
b6d96bed 2963 return fst2;
8dfdb87c 2964}
b6d96bed 2965
895c2d04 2966uint64_t helper_float_recip1_ps(CPUMIPSState *env, uint64_t fdt0)
8dfdb87c 2967{
b6d96bed
TS
2968 uint32_t fst2;
2969 uint32_t fsth2;
2970
05993cd0
AJ
2971 fst2 = float32_div(float32_one, fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
2972 fsth2 = float32_div(float32_one, fdt0 >> 32, &env->active_fpu.fp_status);
5f7319cd 2973 update_fcr31(env, GETPC());
b6d96bed 2974 return ((uint64_t)fsth2 << 32) | fst2;
8dfdb87c
TS
2975}
2976
895c2d04 2977uint64_t helper_float_rsqrt1_d(CPUMIPSState *env, uint64_t fdt0)
8dfdb87c 2978{
b6d96bed
TS
2979 uint64_t fdt2;
2980
f01be154 2981 fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
05993cd0 2982 fdt2 = float64_div(float64_one, fdt2, &env->active_fpu.fp_status);
5f7319cd 2983 update_fcr31(env, GETPC());
b6d96bed 2984 return fdt2;
8dfdb87c 2985}
b6d96bed 2986
895c2d04 2987uint32_t helper_float_rsqrt1_s(CPUMIPSState *env, uint32_t fst0)
8dfdb87c 2988{
b6d96bed
TS
2989 uint32_t fst2;
2990
f01be154 2991 fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status);
05993cd0 2992 fst2 = float32_div(float32_one, fst2, &env->active_fpu.fp_status);
5f7319cd 2993 update_fcr31(env, GETPC());
b6d96bed 2994 return fst2;
8dfdb87c 2995}
b6d96bed 2996
895c2d04 2997uint64_t helper_float_rsqrt1_ps(CPUMIPSState *env, uint64_t fdt0)
8dfdb87c 2998{
b6d96bed
TS
2999 uint32_t fst2;
3000 uint32_t fsth2;
3001
f01be154
TS
3002 fst2 = float32_sqrt(fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
3003 fsth2 = float32_sqrt(fdt0 >> 32, &env->active_fpu.fp_status);
05993cd0
AJ
3004 fst2 = float32_div(float32_one, fst2, &env->active_fpu.fp_status);
3005 fsth2 = float32_div(float32_one, fsth2, &env->active_fpu.fp_status);
5f7319cd 3006 update_fcr31(env, GETPC());
b6d96bed 3007 return ((uint64_t)fsth2 << 32) | fst2;
57fa1fb3 3008}
57fa1fb3 3009
8fc605b8
MR
3010#define FLOAT_RINT(name, bits) \
3011uint ## bits ## _t helper_float_ ## name (CPUMIPSState *env, \
3012 uint ## bits ## _t fs) \
3013{ \
3014 uint ## bits ## _t fdret; \
3015 \
3016 fdret = float ## bits ## _round_to_int(fs, &env->active_fpu.fp_status); \
3017 update_fcr31(env, GETPC()); \
3018 return fdret; \
3019}
3020
3021FLOAT_RINT(rint_s, 32)
3022FLOAT_RINT(rint_d, 64)
3023#undef FLOAT_RINT
3024
3025#define FLOAT_CLASS_SIGNALING_NAN 0x001
3026#define FLOAT_CLASS_QUIET_NAN 0x002
3027#define FLOAT_CLASS_NEGATIVE_INFINITY 0x004
3028#define FLOAT_CLASS_NEGATIVE_NORMAL 0x008
3029#define FLOAT_CLASS_NEGATIVE_SUBNORMAL 0x010
3030#define FLOAT_CLASS_NEGATIVE_ZERO 0x020
3031#define FLOAT_CLASS_POSITIVE_INFINITY 0x040
3032#define FLOAT_CLASS_POSITIVE_NORMAL 0x080
3033#define FLOAT_CLASS_POSITIVE_SUBNORMAL 0x100
3034#define FLOAT_CLASS_POSITIVE_ZERO 0x200
3035
3036#define FLOAT_CLASS(name, bits) \
3037uint ## bits ## _t helper_float_ ## name (uint ## bits ## _t arg) \
3038{ \
3039 if (float ## bits ## _is_signaling_nan(arg)) { \
3040 return FLOAT_CLASS_SIGNALING_NAN; \
3041 } else if (float ## bits ## _is_quiet_nan(arg)) { \
3042 return FLOAT_CLASS_QUIET_NAN; \
3043 } else if (float ## bits ## _is_neg(arg)) { \
3044 if (float ## bits ## _is_infinity(arg)) { \
3045 return FLOAT_CLASS_NEGATIVE_INFINITY; \
3046 } else if (float ## bits ## _is_zero(arg)) { \
3047 return FLOAT_CLASS_NEGATIVE_ZERO; \
3048 } else if (float ## bits ## _is_zero_or_denormal(arg)) { \
3049 return FLOAT_CLASS_NEGATIVE_SUBNORMAL; \
3050 } else { \
3051 return FLOAT_CLASS_NEGATIVE_NORMAL; \
3052 } \
3053 } else { \
3054 if (float ## bits ## _is_infinity(arg)) { \
3055 return FLOAT_CLASS_POSITIVE_INFINITY; \
3056 } else if (float ## bits ## _is_zero(arg)) { \
3057 return FLOAT_CLASS_POSITIVE_ZERO; \
3058 } else if (float ## bits ## _is_zero_or_denormal(arg)) { \
3059 return FLOAT_CLASS_POSITIVE_SUBNORMAL; \
3060 } else { \
3061 return FLOAT_CLASS_POSITIVE_NORMAL; \
3062 } \
3063 } \
3064}
3065
3066FLOAT_CLASS(class_s, 32)
3067FLOAT_CLASS(class_d, 64)
3068#undef FLOAT_CLASS
3069
fd4a04eb 3070/* binary operations */
b6d96bed 3071#define FLOAT_BINOP(name) \
895c2d04
BS
3072uint64_t helper_float_ ## name ## _d(CPUMIPSState *env, \
3073 uint64_t fdt0, uint64_t fdt1) \
b6d96bed
TS
3074{ \
3075 uint64_t dt2; \
3076 \
f01be154 3077 dt2 = float64_ ## name (fdt0, fdt1, &env->active_fpu.fp_status); \
5f7319cd 3078 update_fcr31(env, GETPC()); \
b6d96bed
TS
3079 return dt2; \
3080} \
3081 \
895c2d04
BS
3082uint32_t helper_float_ ## name ## _s(CPUMIPSState *env, \
3083 uint32_t fst0, uint32_t fst1) \
b6d96bed
TS
3084{ \
3085 uint32_t wt2; \
3086 \
f01be154 3087 wt2 = float32_ ## name (fst0, fst1, &env->active_fpu.fp_status); \
5f7319cd 3088 update_fcr31(env, GETPC()); \
b6d96bed
TS
3089 return wt2; \
3090} \
3091 \
895c2d04
BS
3092uint64_t helper_float_ ## name ## _ps(CPUMIPSState *env, \
3093 uint64_t fdt0, \
3094 uint64_t fdt1) \
b6d96bed
TS
3095{ \
3096 uint32_t fst0 = fdt0 & 0XFFFFFFFF; \
3097 uint32_t fsth0 = fdt0 >> 32; \
3098 uint32_t fst1 = fdt1 & 0XFFFFFFFF; \
3099 uint32_t fsth1 = fdt1 >> 32; \
3100 uint32_t wt2; \
3101 uint32_t wth2; \
3102 \
f01be154
TS
3103 wt2 = float32_ ## name (fst0, fst1, &env->active_fpu.fp_status); \
3104 wth2 = float32_ ## name (fsth0, fsth1, &env->active_fpu.fp_status); \
5f7319cd 3105 update_fcr31(env, GETPC()); \
b6d96bed 3106 return ((uint64_t)wth2 << 32) | wt2; \
fd4a04eb 3107}
b6d96bed 3108
fd4a04eb
TS
3109FLOAT_BINOP(add)
3110FLOAT_BINOP(sub)
3111FLOAT_BINOP(mul)
3112FLOAT_BINOP(div)
3113#undef FLOAT_BINOP
3114
8dfdb87c 3115/* MIPS specific binary operations */
895c2d04 3116uint64_t helper_float_recip2_d(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
8dfdb87c 3117{
f01be154 3118 fdt2 = float64_mul(fdt0, fdt2, &env->active_fpu.fp_status);
05993cd0 3119 fdt2 = float64_chs(float64_sub(fdt2, float64_one, &env->active_fpu.fp_status));
5f7319cd 3120 update_fcr31(env, GETPC());
b6d96bed 3121 return fdt2;
8dfdb87c 3122}
b6d96bed 3123
895c2d04 3124uint32_t helper_float_recip2_s(CPUMIPSState *env, uint32_t fst0, uint32_t fst2)
8dfdb87c 3125{
f01be154 3126 fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
05993cd0 3127 fst2 = float32_chs(float32_sub(fst2, float32_one, &env->active_fpu.fp_status));
5f7319cd 3128 update_fcr31(env, GETPC());
b6d96bed 3129 return fst2;
8dfdb87c 3130}
b6d96bed 3131
895c2d04 3132uint64_t helper_float_recip2_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
8dfdb87c 3133{
b6d96bed
TS
3134 uint32_t fst0 = fdt0 & 0XFFFFFFFF;
3135 uint32_t fsth0 = fdt0 >> 32;
3136 uint32_t fst2 = fdt2 & 0XFFFFFFFF;
3137 uint32_t fsth2 = fdt2 >> 32;
3138
f01be154
TS
3139 fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
3140 fsth2 = float32_mul(fsth0, fsth2, &env->active_fpu.fp_status);
05993cd0
AJ
3141 fst2 = float32_chs(float32_sub(fst2, float32_one, &env->active_fpu.fp_status));
3142 fsth2 = float32_chs(float32_sub(fsth2, float32_one, &env->active_fpu.fp_status));
5f7319cd 3143 update_fcr31(env, GETPC());
b6d96bed 3144 return ((uint64_t)fsth2 << 32) | fst2;
8dfdb87c
TS
3145}
3146
895c2d04 3147uint64_t helper_float_rsqrt2_d(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
8dfdb87c 3148{
f01be154 3149 fdt2 = float64_mul(fdt0, fdt2, &env->active_fpu.fp_status);
05993cd0 3150 fdt2 = float64_sub(fdt2, float64_one, &env->active_fpu.fp_status);
f01be154 3151 fdt2 = float64_chs(float64_div(fdt2, FLOAT_TWO64, &env->active_fpu.fp_status));
5f7319cd 3152 update_fcr31(env, GETPC());
b6d96bed 3153 return fdt2;
8dfdb87c 3154}
b6d96bed 3155
895c2d04 3156uint32_t helper_float_rsqrt2_s(CPUMIPSState *env, uint32_t fst0, uint32_t fst2)
8dfdb87c 3157{
f01be154 3158 fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
05993cd0 3159 fst2 = float32_sub(fst2, float32_one, &env->active_fpu.fp_status);
f01be154 3160 fst2 = float32_chs(float32_div(fst2, FLOAT_TWO32, &env->active_fpu.fp_status));
5f7319cd 3161 update_fcr31(env, GETPC());
b6d96bed 3162 return fst2;
8dfdb87c 3163}
b6d96bed 3164
895c2d04 3165uint64_t helper_float_rsqrt2_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
8dfdb87c 3166{
b6d96bed
TS
3167 uint32_t fst0 = fdt0 & 0XFFFFFFFF;
3168 uint32_t fsth0 = fdt0 >> 32;
3169 uint32_t fst2 = fdt2 & 0XFFFFFFFF;
3170 uint32_t fsth2 = fdt2 >> 32;
3171
f01be154
TS
3172 fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
3173 fsth2 = float32_mul(fsth0, fsth2, &env->active_fpu.fp_status);
05993cd0
AJ
3174 fst2 = float32_sub(fst2, float32_one, &env->active_fpu.fp_status);
3175 fsth2 = float32_sub(fsth2, float32_one, &env->active_fpu.fp_status);
f01be154
TS
3176 fst2 = float32_chs(float32_div(fst2, FLOAT_TWO32, &env->active_fpu.fp_status));
3177 fsth2 = float32_chs(float32_div(fsth2, FLOAT_TWO32, &env->active_fpu.fp_status));
5f7319cd 3178 update_fcr31(env, GETPC());
b6d96bed 3179 return ((uint64_t)fsth2 << 32) | fst2;
57fa1fb3 3180}
57fa1fb3 3181
895c2d04 3182uint64_t helper_float_addr_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt1)
fd4a04eb 3183{
b6d96bed
TS
3184 uint32_t fst0 = fdt0 & 0XFFFFFFFF;
3185 uint32_t fsth0 = fdt0 >> 32;
3186 uint32_t fst1 = fdt1 & 0XFFFFFFFF;
3187 uint32_t fsth1 = fdt1 >> 32;
3188 uint32_t fst2;
3189 uint32_t fsth2;
3190
f01be154
TS
3191 fst2 = float32_add (fst0, fsth0, &env->active_fpu.fp_status);
3192 fsth2 = float32_add (fst1, fsth1, &env->active_fpu.fp_status);
5f7319cd 3193 update_fcr31(env, GETPC());
b6d96bed 3194 return ((uint64_t)fsth2 << 32) | fst2;
fd4a04eb
TS
3195}
3196
895c2d04 3197uint64_t helper_float_mulr_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt1)
57fa1fb3 3198{
b6d96bed
TS
3199 uint32_t fst0 = fdt0 & 0XFFFFFFFF;
3200 uint32_t fsth0 = fdt0 >> 32;
3201 uint32_t fst1 = fdt1 & 0XFFFFFFFF;
3202 uint32_t fsth1 = fdt1 >> 32;
3203 uint32_t fst2;
3204 uint32_t fsth2;
3205
f01be154
TS
3206 fst2 = float32_mul (fst0, fsth0, &env->active_fpu.fp_status);
3207 fsth2 = float32_mul (fst1, fsth1, &env->active_fpu.fp_status);
5f7319cd 3208 update_fcr31(env, GETPC());
b6d96bed 3209 return ((uint64_t)fsth2 << 32) | fst2;
57fa1fb3
TS
3210}
3211
8fc605b8
MR
3212#define FLOAT_MINMAX(name, bits, minmaxfunc) \
3213uint ## bits ## _t helper_float_ ## name (CPUMIPSState *env, \
3214 uint ## bits ## _t fs, \
3215 uint ## bits ## _t ft) \
3216{ \
3217 uint ## bits ## _t fdret; \
3218 \
3219 fdret = float ## bits ## _ ## minmaxfunc(fs, ft, \
3220 &env->active_fpu.fp_status); \
3221 update_fcr31(env, GETPC()); \
3222 return fdret; \
3223}
3224
3225FLOAT_MINMAX(max_s, 32, maxnum)
3226FLOAT_MINMAX(max_d, 64, maxnum)
3227FLOAT_MINMAX(maxa_s, 32, maxnummag)
3228FLOAT_MINMAX(maxa_d, 64, maxnummag)
3229
3230FLOAT_MINMAX(min_s, 32, minnum)
3231FLOAT_MINMAX(min_d, 64, minnum)
3232FLOAT_MINMAX(mina_s, 32, minnummag)
3233FLOAT_MINMAX(mina_d, 64, minnummag)
3234#undef FLOAT_MINMAX
3235
3236/* ternary operations */
3237#define UNFUSED_FMA(prefix, a, b, c, flags) \
3238{ \
3239 a = prefix##_mul(a, b, &env->active_fpu.fp_status); \
3240 if ((flags) & float_muladd_negate_c) { \
3241 a = prefix##_sub(a, c, &env->active_fpu.fp_status); \
3242 } else { \
3243 a = prefix##_add(a, c, &env->active_fpu.fp_status); \
3244 } \
3245 if ((flags) & float_muladd_negate_result) { \
3246 a = prefix##_chs(a); \
3247 } \
3248}
3249
3250/* FMA based operations */
3251#define FLOAT_FMA(name, type) \
3252uint64_t helper_float_ ## name ## _d(CPUMIPSState *env, \
3253 uint64_t fdt0, uint64_t fdt1, \
3254 uint64_t fdt2) \
3255{ \
3256 UNFUSED_FMA(float64, fdt0, fdt1, fdt2, type); \
3257 update_fcr31(env, GETPC()); \
3258 return fdt0; \
3259} \
3260 \
3261uint32_t helper_float_ ## name ## _s(CPUMIPSState *env, \
3262 uint32_t fst0, uint32_t fst1, \
3263 uint32_t fst2) \
3264{ \
3265 UNFUSED_FMA(float32, fst0, fst1, fst2, type); \
3266 update_fcr31(env, GETPC()); \
3267 return fst0; \
3268} \
3269 \
3270uint64_t helper_float_ ## name ## _ps(CPUMIPSState *env, \
3271 uint64_t fdt0, uint64_t fdt1, \
3272 uint64_t fdt2) \
3273{ \
3274 uint32_t fst0 = fdt0 & 0XFFFFFFFF; \
3275 uint32_t fsth0 = fdt0 >> 32; \
3276 uint32_t fst1 = fdt1 & 0XFFFFFFFF; \
3277 uint32_t fsth1 = fdt1 >> 32; \
3278 uint32_t fst2 = fdt2 & 0XFFFFFFFF; \
3279 uint32_t fsth2 = fdt2 >> 32; \
3280 \
3281 UNFUSED_FMA(float32, fst0, fst1, fst2, type); \
3282 UNFUSED_FMA(float32, fsth0, fsth1, fsth2, type); \
3283 update_fcr31(env, GETPC()); \
3284 return ((uint64_t)fsth0 << 32) | fst0; \
3285}
3286FLOAT_FMA(madd, 0)
3287FLOAT_FMA(msub, float_muladd_negate_c)
3288FLOAT_FMA(nmadd, float_muladd_negate_result)
3289FLOAT_FMA(nmsub, float_muladd_negate_result | float_muladd_negate_c)
3290#undef FLOAT_FMA
3291
3292#define FLOAT_FMADDSUB(name, bits, muladd_arg) \
3293uint ## bits ## _t helper_float_ ## name (CPUMIPSState *env, \
3294 uint ## bits ## _t fs, \
3295 uint ## bits ## _t ft, \
3296 uint ## bits ## _t fd) \
3297{ \
3298 uint ## bits ## _t fdret; \
3299 \
3300 fdret = float ## bits ## _muladd(fs, ft, fd, muladd_arg, \
3301 &env->active_fpu.fp_status); \
3302 update_fcr31(env, GETPC()); \
3303 return fdret; \
3304}
3305
3306FLOAT_FMADDSUB(maddf_s, 32, 0)
3307FLOAT_FMADDSUB(maddf_d, 64, 0)
3308FLOAT_FMADDSUB(msubf_s, 32, float_muladd_negate_product)
3309FLOAT_FMADDSUB(msubf_d, 64, float_muladd_negate_product)
3310#undef FLOAT_FMADDSUB
3311
8dfdb87c 3312/* compare operations */
b6d96bed 3313#define FOP_COND_D(op, cond) \
895c2d04
BS
3314void helper_cmp_d_ ## op(CPUMIPSState *env, uint64_t fdt0, \
3315 uint64_t fdt1, int cc) \
b6d96bed 3316{ \
6a385343 3317 int c; \
6a385343 3318 c = cond; \
5f7319cd 3319 update_fcr31(env, GETPC()); \
b6d96bed 3320 if (c) \
f01be154 3321 SET_FP_COND(cc, env->active_fpu); \
b6d96bed 3322 else \
f01be154 3323 CLEAR_FP_COND(cc, env->active_fpu); \
b6d96bed 3324} \
895c2d04
BS
3325void helper_cmpabs_d_ ## op(CPUMIPSState *env, uint64_t fdt0, \
3326 uint64_t fdt1, int cc) \
b6d96bed
TS
3327{ \
3328 int c; \
3329 fdt0 = float64_abs(fdt0); \
3330 fdt1 = float64_abs(fdt1); \
3331 c = cond; \
5f7319cd 3332 update_fcr31(env, GETPC()); \
b6d96bed 3333 if (c) \
f01be154 3334 SET_FP_COND(cc, env->active_fpu); \
b6d96bed 3335 else \
f01be154 3336 CLEAR_FP_COND(cc, env->active_fpu); \
fd4a04eb
TS
3337}
3338
fd4a04eb 3339/* NOTE: the comma operator will make "cond" to eval to false,
3a599383
AJ
3340 * but float64_unordered_quiet() is still called. */
3341FOP_COND_D(f, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status), 0))
3342FOP_COND_D(un, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status))
06a0e6b1 3343FOP_COND_D(eq, float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
211315fb 3344FOP_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
3345FOP_COND_D(olt, float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
3346FOP_COND_D(ult, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status) || float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
3347FOP_COND_D(ole, float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
3348FOP_COND_D(ule, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status) || float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
fd4a04eb 3349/* NOTE: the comma operator will make "cond" to eval to false,
3a599383
AJ
3350 * but float64_unordered() is still called. */
3351FOP_COND_D(sf, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status), 0))
3352FOP_COND_D(ngle,float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status))
06a0e6b1
AJ
3353FOP_COND_D(seq, float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
3354FOP_COND_D(ngl, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status) || float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
3355FOP_COND_D(lt, float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
3a599383 3356FOP_COND_D(nge, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status) || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
06a0e6b1 3357FOP_COND_D(le, float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
3a599383 3358FOP_COND_D(ngt, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status) || float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
b6d96bed
TS
3359
3360#define FOP_COND_S(op, cond) \
895c2d04
BS
3361void helper_cmp_s_ ## op(CPUMIPSState *env, uint32_t fst0, \
3362 uint32_t fst1, int cc) \
b6d96bed 3363{ \
6a385343 3364 int c; \
6a385343 3365 c = cond; \
5f7319cd 3366 update_fcr31(env, GETPC()); \
b6d96bed 3367 if (c) \
f01be154 3368 SET_FP_COND(cc, env->active_fpu); \
b6d96bed 3369 else \
f01be154 3370 CLEAR_FP_COND(cc, env->active_fpu); \
b6d96bed 3371} \
895c2d04
BS
3372void helper_cmpabs_s_ ## op(CPUMIPSState *env, uint32_t fst0, \
3373 uint32_t fst1, int cc) \
b6d96bed
TS
3374{ \
3375 int c; \
3376 fst0 = float32_abs(fst0); \
3377 fst1 = float32_abs(fst1); \
3378 c = cond; \
5f7319cd 3379 update_fcr31(env, GETPC()); \
b6d96bed 3380 if (c) \
f01be154 3381 SET_FP_COND(cc, env->active_fpu); \
b6d96bed 3382 else \
f01be154 3383 CLEAR_FP_COND(cc, env->active_fpu); \
fd4a04eb
TS
3384}
3385
fd4a04eb 3386/* NOTE: the comma operator will make "cond" to eval to false,
3a599383
AJ
3387 * but float32_unordered_quiet() is still called. */
3388FOP_COND_S(f, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status), 0))
3389FOP_COND_S(un, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status))
06a0e6b1 3390FOP_COND_S(eq, float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status))
211315fb 3391FOP_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
3392FOP_COND_S(olt, float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status))
3393FOP_COND_S(ult, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status))
3394FOP_COND_S(ole, float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status))
3395FOP_COND_S(ule, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status))
fd4a04eb 3396/* NOTE: the comma operator will make "cond" to eval to false,
3a599383
AJ
3397 * but float32_unordered() is still called. */
3398FOP_COND_S(sf, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status), 0))
3399FOP_COND_S(ngle,float32_unordered(fst1, fst0, &env->active_fpu.fp_status))
06a0e6b1
AJ
3400FOP_COND_S(seq, float32_eq(fst0, fst1, &env->active_fpu.fp_status))
3401FOP_COND_S(ngl, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_eq(fst0, fst1, &env->active_fpu.fp_status))
3402FOP_COND_S(lt, float32_lt(fst0, fst1, &env->active_fpu.fp_status))
3a599383 3403FOP_COND_S(nge, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_lt(fst0, fst1, &env->active_fpu.fp_status))
06a0e6b1 3404FOP_COND_S(le, float32_le(fst0, fst1, &env->active_fpu.fp_status))
3a599383 3405FOP_COND_S(ngt, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_le(fst0, fst1, &env->active_fpu.fp_status))
b6d96bed
TS
3406
3407#define FOP_COND_PS(op, condl, condh) \
895c2d04
BS
3408void helper_cmp_ps_ ## op(CPUMIPSState *env, uint64_t fdt0, \
3409 uint64_t fdt1, int cc) \
b6d96bed 3410{ \
6a385343
AJ
3411 uint32_t fst0, fsth0, fst1, fsth1; \
3412 int ch, cl; \
6a385343
AJ
3413 fst0 = fdt0 & 0XFFFFFFFF; \
3414 fsth0 = fdt0 >> 32; \
3415 fst1 = fdt1 & 0XFFFFFFFF; \
3416 fsth1 = fdt1 >> 32; \
3417 cl = condl; \
3418 ch = condh; \
5f7319cd 3419 update_fcr31(env, GETPC()); \
b6d96bed 3420 if (cl) \
f01be154 3421 SET_FP_COND(cc, env->active_fpu); \
b6d96bed 3422 else \
f01be154 3423 CLEAR_FP_COND(cc, env->active_fpu); \
b6d96bed 3424 if (ch) \
f01be154 3425 SET_FP_COND(cc + 1, env->active_fpu); \
b6d96bed 3426 else \
f01be154 3427 CLEAR_FP_COND(cc + 1, env->active_fpu); \
b6d96bed 3428} \
895c2d04
BS
3429void helper_cmpabs_ps_ ## op(CPUMIPSState *env, uint64_t fdt0, \
3430 uint64_t fdt1, int cc) \
b6d96bed 3431{ \
6a385343
AJ
3432 uint32_t fst0, fsth0, fst1, fsth1; \
3433 int ch, cl; \
3434 fst0 = float32_abs(fdt0 & 0XFFFFFFFF); \
3435 fsth0 = float32_abs(fdt0 >> 32); \
3436 fst1 = float32_abs(fdt1 & 0XFFFFFFFF); \
3437 fsth1 = float32_abs(fdt1 >> 32); \
3438 cl = condl; \
3439 ch = condh; \
5f7319cd 3440 update_fcr31(env, GETPC()); \
b6d96bed 3441 if (cl) \
f01be154 3442 SET_FP_COND(cc, env->active_fpu); \
b6d96bed 3443 else \
f01be154 3444 CLEAR_FP_COND(cc, env->active_fpu); \
b6d96bed 3445 if (ch) \
f01be154 3446 SET_FP_COND(cc + 1, env->active_fpu); \
b6d96bed 3447 else \
f01be154 3448 CLEAR_FP_COND(cc + 1, env->active_fpu); \
fd4a04eb
TS
3449}
3450
3451/* NOTE: the comma operator will make "cond" to eval to false,
3a599383
AJ
3452 * but float32_unordered_quiet() is still called. */
3453FOP_COND_PS(f, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status), 0),
3454 (float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status), 0))
3455FOP_COND_PS(un, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status),
3456 float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status))
06a0e6b1
AJ
3457FOP_COND_PS(eq, float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status),
3458 float32_eq_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
211315fb
AJ
3459FOP_COND_PS(ueq, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status),
3460 float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status) || float32_eq_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
06a0e6b1
AJ
3461FOP_COND_PS(olt, float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status),
3462 float32_lt_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
3463FOP_COND_PS(ult, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status),
3464 float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status) || float32_lt_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
3465FOP_COND_PS(ole, float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status),
3466 float32_le_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
3467FOP_COND_PS(ule, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status),
3468 float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status) || float32_le_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
fd4a04eb 3469/* NOTE: the comma operator will make "cond" to eval to false,
3a599383
AJ
3470 * but float32_unordered() is still called. */
3471FOP_COND_PS(sf, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status), 0),
3472 (float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status), 0))
3473FOP_COND_PS(ngle,float32_unordered(fst1, fst0, &env->active_fpu.fp_status),
3474 float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status))
06a0e6b1
AJ
3475FOP_COND_PS(seq, float32_eq(fst0, fst1, &env->active_fpu.fp_status),
3476 float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
3477FOP_COND_PS(ngl, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_eq(fst0, fst1, &env->active_fpu.fp_status),
3478 float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status) || float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
3479FOP_COND_PS(lt, float32_lt(fst0, fst1, &env->active_fpu.fp_status),
3480 float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
3a599383
AJ
3481FOP_COND_PS(nge, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_lt(fst0, fst1, &env->active_fpu.fp_status),
3482 float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status) || float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
06a0e6b1
AJ
3483FOP_COND_PS(le, float32_le(fst0, fst1, &env->active_fpu.fp_status),
3484 float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
3a599383
AJ
3485FOP_COND_PS(ngt, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_le(fst0, fst1, &env->active_fpu.fp_status),
3486 float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status) || float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
3f493883
YK
3487
3488/* R6 compare operations */
3489#define FOP_CONDN_D(op, cond) \
3490uint64_t helper_r6_cmp_d_ ## op(CPUMIPSState * env, uint64_t fdt0, \
3491 uint64_t fdt1) \
3492{ \
3493 uint64_t c; \
3494 c = cond; \
3495 update_fcr31(env, GETPC()); \
3496 if (c) { \
3497 return -1; \
3498 } else { \
3499 return 0; \
3500 } \
3501}
3502
3503/* NOTE: the comma operator will make "cond" to eval to false,
3504 * but float64_unordered_quiet() is still called. */
3505FOP_CONDN_D(af, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status), 0))
3506FOP_CONDN_D(un, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)))
3507FOP_CONDN_D(eq, (float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
3508FOP_CONDN_D(ueq, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
3509 || float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
3510FOP_CONDN_D(lt, (float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
3511FOP_CONDN_D(ult, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
3512 || float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
3513FOP_CONDN_D(le, (float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
3514FOP_CONDN_D(ule, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
3515 || float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
3516/* NOTE: the comma operator will make "cond" to eval to false,
3517 * but float64_unordered() is still called. */
3518FOP_CONDN_D(saf, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status), 0))
3519FOP_CONDN_D(sun, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)))
3520FOP_CONDN_D(seq, (float64_eq(fdt0, fdt1, &env->active_fpu.fp_status)))
3521FOP_CONDN_D(sueq, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)
3522 || float64_eq(fdt0, fdt1, &env->active_fpu.fp_status)))
3523FOP_CONDN_D(slt, (float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)))
3524FOP_CONDN_D(sult, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)
3525 || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)))
3526FOP_CONDN_D(sle, (float64_le(fdt0, fdt1, &env->active_fpu.fp_status)))
3527FOP_CONDN_D(sule, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)
3528 || float64_le(fdt0, fdt1, &env->active_fpu.fp_status)))
3529FOP_CONDN_D(or, (float64_le_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
3530 || float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
3531FOP_CONDN_D(une, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
3532 || float64_lt_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
3533 || float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
3534FOP_CONDN_D(ne, (float64_lt_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
3535 || float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
3536FOP_CONDN_D(sor, (float64_le(fdt1, fdt0, &env->active_fpu.fp_status)
3537 || float64_le(fdt0, fdt1, &env->active_fpu.fp_status)))
3538FOP_CONDN_D(sune, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)
3539 || float64_lt(fdt1, fdt0, &env->active_fpu.fp_status)
3540 || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)))
3541FOP_CONDN_D(sne, (float64_lt(fdt1, fdt0, &env->active_fpu.fp_status)
3542 || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)))
3543
3544#define FOP_CONDN_S(op, cond) \
3545uint32_t helper_r6_cmp_s_ ## op(CPUMIPSState * env, uint32_t fst0, \
3546 uint32_t fst1) \
3547{ \
3548 uint64_t c; \
3549 c = cond; \
3550 update_fcr31(env, GETPC()); \
3551 if (c) { \
3552 return -1; \
3553 } else { \
3554 return 0; \
3555 } \
3556}
3557
3558/* NOTE: the comma operator will make "cond" to eval to false,
3559 * but float32_unordered_quiet() is still called. */
3560FOP_CONDN_S(af, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status), 0))
3561FOP_CONDN_S(un, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)))
3562FOP_CONDN_S(eq, (float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status)))
3563FOP_CONDN_S(ueq, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)
3564 || float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status)))
3565FOP_CONDN_S(lt, (float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status)))
3566FOP_CONDN_S(ult, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)
3567 || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status)))
3568FOP_CONDN_S(le, (float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status)))
3569FOP_CONDN_S(ule, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)
3570 || float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status)))
3571/* NOTE: the comma operator will make "cond" to eval to false,
3572 * but float32_unordered() is still called. */
3573FOP_CONDN_S(saf, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status), 0))
3574FOP_CONDN_S(sun, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status)))
3575FOP_CONDN_S(seq, (float32_eq(fst0, fst1, &env->active_fpu.fp_status)))
3576FOP_CONDN_S(sueq, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status)
3577 || float32_eq(fst0, fst1, &env->active_fpu.fp_status)))
3578FOP_CONDN_S(slt, (float32_lt(fst0, fst1, &env->active_fpu.fp_status)))
3579FOP_CONDN_S(sult, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status)
3580 || float32_lt(fst0, fst1, &env->active_fpu.fp_status)))
3581FOP_CONDN_S(sle, (float32_le(fst0, fst1, &env->active_fpu.fp_status)))
3582FOP_CONDN_S(sule, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status)
3583 || float32_le(fst0, fst1, &env->active_fpu.fp_status)))
3584FOP_CONDN_S(or, (float32_le_quiet(fst1, fst0, &env->active_fpu.fp_status)
3585 || float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status)))
3586FOP_CONDN_S(une, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)
3587 || float32_lt_quiet(fst1, fst0, &env->active_fpu.fp_status)
3588 || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status)))
3589FOP_CONDN_S(ne, (float32_lt_quiet(fst1, fst0, &env->active_fpu.fp_status)
3590 || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status)))
3591FOP_CONDN_S(sor, (float32_le(fst1, fst0, &env->active_fpu.fp_status)
3592 || float32_le(fst0, fst1, &env->active_fpu.fp_status)))
3593FOP_CONDN_S(sune, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status)
3594 || float32_lt(fst1, fst0, &env->active_fpu.fp_status)
3595 || float32_lt(fst0, fst1, &env->active_fpu.fp_status)))
3596FOP_CONDN_S(sne, (float32_lt(fst1, fst0, &env->active_fpu.fp_status)
3597 || float32_lt(fst0, fst1, &env->active_fpu.fp_status)))
f7685877
YK
3598
3599/* MSA */
3600/* Data format min and max values */
3601#define DF_BITS(df) (1 << ((df) + 3))
3602
3603/* Element-by-element access macros */
3604#define DF_ELEMENTS(df) (MSA_WRLEN / DF_BITS(df))
3605
adc370a4
YK
3606#if !defined(CONFIG_USER_ONLY)
3607#define MEMOP_IDX(DF) \
3608 TCGMemOpIdx oi = make_memop_idx(MO_TE | DF | MO_UNALN, \
3609 cpu_mmu_index(env));
3610#else
3611#define MEMOP_IDX(DF)
3612#endif
f7685877 3613
adc370a4
YK
3614#define MSA_LD_DF(DF, TYPE, LD_INSN, ...) \
3615void helper_msa_ld_ ## TYPE(CPUMIPSState *env, uint32_t wd, \
3616 target_ulong addr) \
3617{ \
3618 wr_t *pwd = &(env->active_fpu.fpr[wd].wr); \
3619 wr_t wx; \
3620 int i; \
3621 MEMOP_IDX(DF) \
3622 for (i = 0; i < DF_ELEMENTS(DF); i++) { \
3623 wx.TYPE[i] = LD_INSN(env, addr + (i << DF), ##__VA_ARGS__); \
3624 } \
3625 memcpy(pwd, &wx, sizeof(wr_t)); \
f7685877
YK
3626}
3627
adc370a4
YK
3628#if !defined(CONFIG_USER_ONLY)
3629MSA_LD_DF(DF_BYTE, b, helper_ret_ldub_mmu, oi, GETRA())
3630MSA_LD_DF(DF_HALF, h, helper_ret_lduw_mmu, oi, GETRA())
3631MSA_LD_DF(DF_WORD, w, helper_ret_ldul_mmu, oi, GETRA())
3632MSA_LD_DF(DF_DOUBLE, d, helper_ret_ldq_mmu, oi, GETRA())
3633#else
3634MSA_LD_DF(DF_BYTE, b, cpu_ldub_data)
3635MSA_LD_DF(DF_HALF, h, cpu_lduw_data)
3636MSA_LD_DF(DF_WORD, w, cpu_ldl_data)
3637MSA_LD_DF(DF_DOUBLE, d, cpu_ldq_data)
3638#endif
f7685877 3639
adc370a4
YK
3640#define MSA_PAGESPAN(x) \
3641 ((((x) & ~TARGET_PAGE_MASK) + MSA_WRLEN/8 - 1) >= TARGET_PAGE_SIZE)
3642
3643static inline void ensure_writable_pages(CPUMIPSState *env,
3644 target_ulong addr,
3645 int mmu_idx,
3646 uintptr_t retaddr)
3647{
3648#if !defined(CONFIG_USER_ONLY)
3649 target_ulong page_addr;
3650 if (unlikely(MSA_PAGESPAN(addr))) {
3651 /* first page */
3652 probe_write(env, addr, mmu_idx, retaddr);
3653 /* second page */
3654 page_addr = (addr & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
3655 probe_write(env, page_addr, mmu_idx, retaddr);
f7685877 3656 }
adc370a4 3657#endif
f7685877 3658}
adc370a4
YK
3659
3660#define MSA_ST_DF(DF, TYPE, ST_INSN, ...) \
3661void helper_msa_st_ ## TYPE(CPUMIPSState *env, uint32_t wd, \
3662 target_ulong addr) \
3663{ \
3664 wr_t *pwd = &(env->active_fpu.fpr[wd].wr); \
3665 int mmu_idx = cpu_mmu_index(env); \
3666 int i; \
3667 MEMOP_IDX(DF) \
3668 ensure_writable_pages(env, addr, mmu_idx, GETRA()); \
3669 for (i = 0; i < DF_ELEMENTS(DF); i++) { \
3670 ST_INSN(env, addr + (i << DF), pwd->TYPE[i], ##__VA_ARGS__); \
3671 } \
3672}
3673
3674#if !defined(CONFIG_USER_ONLY)
3675MSA_ST_DF(DF_BYTE, b, helper_ret_stb_mmu, oi, GETRA())
3676MSA_ST_DF(DF_HALF, h, helper_ret_stw_mmu, oi, GETRA())
3677MSA_ST_DF(DF_WORD, w, helper_ret_stl_mmu, oi, GETRA())
3678MSA_ST_DF(DF_DOUBLE, d, helper_ret_stq_mmu, oi, GETRA())
3679#else
3680MSA_ST_DF(DF_BYTE, b, cpu_stb_data)
3681MSA_ST_DF(DF_HALF, h, cpu_stw_data)
3682MSA_ST_DF(DF_WORD, w, cpu_stl_data)
3683MSA_ST_DF(DF_DOUBLE, d, cpu_stq_data)
3684#endif
This page took 1.508006 seconds and 4 git commands to generate.