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