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