blob: 2bfdd5002f62188b50bf6d0c7dd78665920ce81c [file] [log] [blame]
bellard6af0bf92005-07-02 14:58:51 +00001/*
2 * MIPS emulation helpers for qemu.
ths5fafdf22007-09-16 21:08:06 +00003 *
bellard6af0bf92005-07-02 14:58:51 +00004 * 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
Blue Swirl8167ee82009-07-16 20:47:01 +000017 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
bellard6af0bf92005-07-02 14:58:51 +000018 */
ths2d0e9442007-04-02 15:54:05 +000019#include <stdlib.h>
bellard6af0bf92005-07-02 14:58:51 +000020#include "exec.h"
21
ths05f778c2007-10-27 13:05:54 +000022#include "host-utils.h"
23
pbrooka7812ae2008-11-17 14:43:54 +000024#include "helper.h"
bellard6af0bf92005-07-02 14:58:51 +000025/*****************************************************************************/
26/* Exceptions processing helpers */
bellard6af0bf92005-07-02 14:58:51 +000027
aurel32c01fccd2009-03-08 00:06:01 +000028void helper_raise_exception_err (uint32_t exception, int error_code)
bellard6af0bf92005-07-02 14:58:51 +000029{
30#if 1
aliguori93fcfe32009-01-15 22:34:14 +000031 if (exception < 0x100)
32 qemu_log("%s: %d %d\n", __func__, exception, error_code);
bellard6af0bf92005-07-02 14:58:51 +000033#endif
34 env->exception_index = exception;
35 env->error_code = error_code;
bellard6af0bf92005-07-02 14:58:51 +000036 cpu_loop_exit();
37}
38
aurel32c01fccd2009-03-08 00:06:01 +000039void helper_raise_exception (uint32_t exception)
bellard6af0bf92005-07-02 14:58:51 +000040{
aurel32c01fccd2009-03-08 00:06:01 +000041 helper_raise_exception_err(exception, 0);
bellard6af0bf92005-07-02 14:58:51 +000042}
43
aurel32c01fccd2009-03-08 00:06:01 +000044void helper_interrupt_restart (void)
ths48d38ca2008-05-18 22:50:49 +000045{
46 if (!(env->CP0_Status & (1 << CP0St_EXL)) &&
47 !(env->CP0_Status & (1 << CP0St_ERL)) &&
48 !(env->hflags & MIPS_HFLAG_DM) &&
49 (env->CP0_Status & (1 << CP0St_IE)) &&
50 (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask)) {
51 env->CP0_Cause &= ~(0x1f << CP0Ca_EC);
aurel32c01fccd2009-03-08 00:06:01 +000052 helper_raise_exception(EXCP_EXT_INTERRUPT);
ths48d38ca2008-05-18 22:50:49 +000053 }
54}
55
thsf9480ff2008-12-20 19:42:14 +000056#if !defined(CONFIG_USER_ONLY)
57static void do_restore_state (void *pc_ptr)
bellard4ad40f32005-12-05 19:59:36 +000058{
bellarda6079222008-05-10 15:42:17 +000059 TranslationBlock *tb;
60 unsigned long pc = (unsigned long) pc_ptr;
61
62 tb = tb_find_pc (pc);
63 if (tb) {
64 cpu_restore_state (tb, env, pc, NULL);
65 }
bellard4ad40f32005-12-05 19:59:36 +000066}
thsf9480ff2008-12-20 19:42:14 +000067#endif
bellard4ad40f32005-12-05 19:59:36 +000068
Aurelien Jarno0ae43042009-11-30 15:32:47 +010069#if defined(CONFIG_USER_ONLY)
70#define HELPER_LD(name, insn, type) \
71static inline type do_##name(target_ulong addr, int mem_idx) \
72{ \
73 return (type) insn##_raw(addr); \
74}
75#else
76#define HELPER_LD(name, insn, type) \
77static inline type do_##name(target_ulong addr, int mem_idx) \
78{ \
79 switch (mem_idx) \
80 { \
81 case 0: return (type) insn##_kernel(addr); break; \
82 case 1: return (type) insn##_super(addr); break; \
83 default: \
84 case 2: return (type) insn##_user(addr); break; \
85 } \
86}
87#endif
88HELPER_LD(lbu, ldub, uint8_t)
89HELPER_LD(lw, ldl, int32_t)
90#ifdef TARGET_MIPS64
91HELPER_LD(ld, ldq, int64_t)
92#endif
93#undef HELPER_LD
94
95#if defined(CONFIG_USER_ONLY)
96#define HELPER_ST(name, insn, type) \
97static inline void do_##name(target_ulong addr, type val, int mem_idx) \
98{ \
99 insn##_raw(addr, val); \
100}
101#else
102#define HELPER_ST(name, insn, type) \
103static inline void do_##name(target_ulong addr, type val, int mem_idx) \
104{ \
105 switch (mem_idx) \
106 { \
107 case 0: insn##_kernel(addr, val); break; \
108 case 1: insn##_super(addr, val); break; \
109 default: \
110 case 2: insn##_user(addr, val); break; \
111 } \
112}
113#endif
114HELPER_ST(sb, stb, uint8_t)
115HELPER_ST(sw, stl, uint32_t)
116#ifdef TARGET_MIPS64
117HELPER_ST(sd, stq, uint64_t)
118#endif
119#undef HELPER_ST
120
aurel32d9bea112009-04-15 14:41:44 +0000121target_ulong helper_clo (target_ulong arg1)
ths30898802008-05-21 02:04:15 +0000122{
aurel32d9bea112009-04-15 14:41:44 +0000123 return clo32(arg1);
ths30898802008-05-21 02:04:15 +0000124}
125
aurel32d9bea112009-04-15 14:41:44 +0000126target_ulong helper_clz (target_ulong arg1)
ths30898802008-05-21 02:04:15 +0000127{
aurel32d9bea112009-04-15 14:41:44 +0000128 return clz32(arg1);
ths30898802008-05-21 02:04:15 +0000129}
130
thsd26bc212007-11-08 18:05:37 +0000131#if defined(TARGET_MIPS64)
aurel32d9bea112009-04-15 14:41:44 +0000132target_ulong helper_dclo (target_ulong arg1)
thsc570fd12006-12-21 01:19:56 +0000133{
aurel32d9bea112009-04-15 14:41:44 +0000134 return clo64(arg1);
thsc570fd12006-12-21 01:19:56 +0000135}
136
aurel32d9bea112009-04-15 14:41:44 +0000137target_ulong helper_dclz (target_ulong arg1)
thsc570fd12006-12-21 01:19:56 +0000138{
aurel32d9bea112009-04-15 14:41:44 +0000139 return clz64(arg1);
thsc570fd12006-12-21 01:19:56 +0000140}
thsd26bc212007-11-08 18:05:37 +0000141#endif /* TARGET_MIPS64 */
thsc570fd12006-12-21 01:19:56 +0000142
bellard6af0bf92005-07-02 14:58:51 +0000143/* 64 bits arithmetic for 32 bits hosts */
thsc904ef02008-07-23 16:16:31 +0000144static inline uint64_t get_HILO (void)
bellard6af0bf92005-07-02 14:58:51 +0000145{
thsb5dc7732008-06-27 10:02:35 +0000146 return ((uint64_t)(env->active_tc.HI[0]) << 32) | (uint32_t)env->active_tc.LO[0];
bellard6af0bf92005-07-02 14:58:51 +0000147}
148
thsc904ef02008-07-23 16:16:31 +0000149static inline void set_HILO (uint64_t HILO)
bellard6af0bf92005-07-02 14:58:51 +0000150{
thsb5dc7732008-06-27 10:02:35 +0000151 env->active_tc.LO[0] = (int32_t)HILO;
152 env->active_tc.HI[0] = (int32_t)(HILO >> 32);
bellard6af0bf92005-07-02 14:58:51 +0000153}
154
aurel32d9bea112009-04-15 14:41:44 +0000155static inline void set_HIT0_LO (target_ulong arg1, uint64_t HILO)
thse9c71dd2007-12-25 20:46:56 +0000156{
thsb5dc7732008-06-27 10:02:35 +0000157 env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF);
aurel32d9bea112009-04-15 14:41:44 +0000158 arg1 = env->active_tc.HI[0] = (int32_t)(HILO >> 32);
thse9c71dd2007-12-25 20:46:56 +0000159}
160
aurel32d9bea112009-04-15 14:41:44 +0000161static inline void set_HI_LOT0 (target_ulong arg1, uint64_t HILO)
thse9c71dd2007-12-25 20:46:56 +0000162{
aurel32d9bea112009-04-15 14:41:44 +0000163 arg1 = env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF);
thsb5dc7732008-06-27 10:02:35 +0000164 env->active_tc.HI[0] = (int32_t)(HILO >> 32);
thse9c71dd2007-12-25 20:46:56 +0000165}
166
thse9c71dd2007-12-25 20:46:56 +0000167/* Multiplication variants of the vr54xx. */
aurel32d9bea112009-04-15 14:41:44 +0000168target_ulong helper_muls (target_ulong arg1, target_ulong arg2)
thse9c71dd2007-12-25 20:46:56 +0000169{
aurel32d9bea112009-04-15 14:41:44 +0000170 set_HI_LOT0(arg1, 0 - ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
thsbe24bb42008-06-23 12:57:09 +0000171
aurel32d9bea112009-04-15 14:41:44 +0000172 return arg1;
thse9c71dd2007-12-25 20:46:56 +0000173}
174
aurel32d9bea112009-04-15 14:41:44 +0000175target_ulong helper_mulsu (target_ulong arg1, target_ulong arg2)
thse9c71dd2007-12-25 20:46:56 +0000176{
aurel32d9bea112009-04-15 14:41:44 +0000177 set_HI_LOT0(arg1, 0 - ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
thsbe24bb42008-06-23 12:57:09 +0000178
aurel32d9bea112009-04-15 14:41:44 +0000179 return arg1;
thse9c71dd2007-12-25 20:46:56 +0000180}
181
aurel32d9bea112009-04-15 14:41:44 +0000182target_ulong helper_macc (target_ulong arg1, target_ulong arg2)
thse9c71dd2007-12-25 20:46:56 +0000183{
aurel32d9bea112009-04-15 14:41:44 +0000184 set_HI_LOT0(arg1, ((int64_t)get_HILO()) + ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
thsbe24bb42008-06-23 12:57:09 +0000185
aurel32d9bea112009-04-15 14:41:44 +0000186 return arg1;
thse9c71dd2007-12-25 20:46:56 +0000187}
188
aurel32d9bea112009-04-15 14:41:44 +0000189target_ulong helper_macchi (target_ulong arg1, target_ulong arg2)
thse9c71dd2007-12-25 20:46:56 +0000190{
aurel32d9bea112009-04-15 14:41:44 +0000191 set_HIT0_LO(arg1, ((int64_t)get_HILO()) + ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
thsbe24bb42008-06-23 12:57:09 +0000192
aurel32d9bea112009-04-15 14:41:44 +0000193 return arg1;
thse9c71dd2007-12-25 20:46:56 +0000194}
195
aurel32d9bea112009-04-15 14:41:44 +0000196target_ulong helper_maccu (target_ulong arg1, target_ulong arg2)
thse9c71dd2007-12-25 20:46:56 +0000197{
aurel32d9bea112009-04-15 14:41:44 +0000198 set_HI_LOT0(arg1, ((uint64_t)get_HILO()) + ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
thsbe24bb42008-06-23 12:57:09 +0000199
aurel32d9bea112009-04-15 14:41:44 +0000200 return arg1;
thse9c71dd2007-12-25 20:46:56 +0000201}
202
aurel32d9bea112009-04-15 14:41:44 +0000203target_ulong helper_macchiu (target_ulong arg1, target_ulong arg2)
thse9c71dd2007-12-25 20:46:56 +0000204{
aurel32d9bea112009-04-15 14:41:44 +0000205 set_HIT0_LO(arg1, ((uint64_t)get_HILO()) + ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
thsbe24bb42008-06-23 12:57:09 +0000206
aurel32d9bea112009-04-15 14:41:44 +0000207 return arg1;
thse9c71dd2007-12-25 20:46:56 +0000208}
209
aurel32d9bea112009-04-15 14:41:44 +0000210target_ulong helper_msac (target_ulong arg1, target_ulong arg2)
thse9c71dd2007-12-25 20:46:56 +0000211{
aurel32d9bea112009-04-15 14:41:44 +0000212 set_HI_LOT0(arg1, ((int64_t)get_HILO()) - ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
thsbe24bb42008-06-23 12:57:09 +0000213
aurel32d9bea112009-04-15 14:41:44 +0000214 return arg1;
thse9c71dd2007-12-25 20:46:56 +0000215}
216
aurel32d9bea112009-04-15 14:41:44 +0000217target_ulong helper_msachi (target_ulong arg1, target_ulong arg2)
thse9c71dd2007-12-25 20:46:56 +0000218{
aurel32d9bea112009-04-15 14:41:44 +0000219 set_HIT0_LO(arg1, ((int64_t)get_HILO()) - ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
thsbe24bb42008-06-23 12:57:09 +0000220
aurel32d9bea112009-04-15 14:41:44 +0000221 return arg1;
thse9c71dd2007-12-25 20:46:56 +0000222}
223
aurel32d9bea112009-04-15 14:41:44 +0000224target_ulong helper_msacu (target_ulong arg1, target_ulong arg2)
thse9c71dd2007-12-25 20:46:56 +0000225{
aurel32d9bea112009-04-15 14:41:44 +0000226 set_HI_LOT0(arg1, ((uint64_t)get_HILO()) - ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
thsbe24bb42008-06-23 12:57:09 +0000227
aurel32d9bea112009-04-15 14:41:44 +0000228 return arg1;
thse9c71dd2007-12-25 20:46:56 +0000229}
230
aurel32d9bea112009-04-15 14:41:44 +0000231target_ulong helper_msachiu (target_ulong arg1, target_ulong arg2)
thse9c71dd2007-12-25 20:46:56 +0000232{
aurel32d9bea112009-04-15 14:41:44 +0000233 set_HIT0_LO(arg1, ((uint64_t)get_HILO()) - ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
thsbe24bb42008-06-23 12:57:09 +0000234
aurel32d9bea112009-04-15 14:41:44 +0000235 return arg1;
thse9c71dd2007-12-25 20:46:56 +0000236}
237
aurel32d9bea112009-04-15 14:41:44 +0000238target_ulong helper_mulhi (target_ulong arg1, target_ulong arg2)
thse9c71dd2007-12-25 20:46:56 +0000239{
aurel32d9bea112009-04-15 14:41:44 +0000240 set_HIT0_LO(arg1, (int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2);
thsbe24bb42008-06-23 12:57:09 +0000241
aurel32d9bea112009-04-15 14:41:44 +0000242 return arg1;
thse9c71dd2007-12-25 20:46:56 +0000243}
244
aurel32d9bea112009-04-15 14:41:44 +0000245target_ulong helper_mulhiu (target_ulong arg1, target_ulong arg2)
thse9c71dd2007-12-25 20:46:56 +0000246{
aurel32d9bea112009-04-15 14:41:44 +0000247 set_HIT0_LO(arg1, (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2);
thsbe24bb42008-06-23 12:57:09 +0000248
aurel32d9bea112009-04-15 14:41:44 +0000249 return arg1;
thse9c71dd2007-12-25 20:46:56 +0000250}
251
aurel32d9bea112009-04-15 14:41:44 +0000252target_ulong helper_mulshi (target_ulong arg1, target_ulong arg2)
thse9c71dd2007-12-25 20:46:56 +0000253{
aurel32d9bea112009-04-15 14:41:44 +0000254 set_HIT0_LO(arg1, 0 - ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
thsbe24bb42008-06-23 12:57:09 +0000255
aurel32d9bea112009-04-15 14:41:44 +0000256 return arg1;
thse9c71dd2007-12-25 20:46:56 +0000257}
258
aurel32d9bea112009-04-15 14:41:44 +0000259target_ulong helper_mulshiu (target_ulong arg1, target_ulong arg2)
thse9c71dd2007-12-25 20:46:56 +0000260{
aurel32d9bea112009-04-15 14:41:44 +0000261 set_HIT0_LO(arg1, 0 - ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
thsbe24bb42008-06-23 12:57:09 +0000262
aurel32d9bea112009-04-15 14:41:44 +0000263 return arg1;
thse9c71dd2007-12-25 20:46:56 +0000264}
bellard6af0bf92005-07-02 14:58:51 +0000265
ths214c4652008-06-12 12:43:29 +0000266#ifdef TARGET_MIPS64
aurel32d9bea112009-04-15 14:41:44 +0000267void helper_dmult (target_ulong arg1, target_ulong arg2)
ths214c4652008-06-12 12:43:29 +0000268{
aurel32d9bea112009-04-15 14:41:44 +0000269 muls64(&(env->active_tc.LO[0]), &(env->active_tc.HI[0]), arg1, arg2);
ths214c4652008-06-12 12:43:29 +0000270}
271
aurel32d9bea112009-04-15 14:41:44 +0000272void helper_dmultu (target_ulong arg1, target_ulong arg2)
ths214c4652008-06-12 12:43:29 +0000273{
aurel32d9bea112009-04-15 14:41:44 +0000274 mulu64(&(env->active_tc.LO[0]), &(env->active_tc.HI[0]), arg1, arg2);
ths214c4652008-06-12 12:43:29 +0000275}
276#endif
277
Aurelien Jarnoe7139c42009-11-30 15:39:54 +0100278#ifndef CONFIG_USER_ONLY
Aurelien Jarnoc36bbb22010-02-06 17:02:45 +0100279
280static inline target_phys_addr_t do_translate_address(target_ulong address, int rw)
281{
282 target_phys_addr_t lladdr;
283
284 lladdr = cpu_mips_translate_address(env, address, rw);
285
286 if (lladdr == -1LL) {
287 cpu_loop_exit();
288 } else {
289 return lladdr;
290 }
291}
292
Aurelien Jarnoe7139c42009-11-30 15:39:54 +0100293#define HELPER_LD_ATOMIC(name, insn) \
294target_ulong helper_##name(target_ulong arg, int mem_idx) \
295{ \
Aurelien Jarnoc36bbb22010-02-06 17:02:45 +0100296 env->lladdr = do_translate_address(arg, 0); \
Aurelien Jarnoe7139c42009-11-30 15:39:54 +0100297 env->llval = do_##insn(arg, mem_idx); \
298 return env->llval; \
299}
300HELPER_LD_ATOMIC(ll, lw)
301#ifdef TARGET_MIPS64
302HELPER_LD_ATOMIC(lld, ld)
303#endif
304#undef HELPER_LD_ATOMIC
305
306#define HELPER_ST_ATOMIC(name, ld_insn, st_insn, almask) \
307target_ulong helper_##name(target_ulong arg1, target_ulong arg2, int mem_idx) \
308{ \
309 target_long tmp; \
310 \
311 if (arg2 & almask) { \
312 env->CP0_BadVAddr = arg2; \
313 helper_raise_exception(EXCP_AdES); \
314 } \
Aurelien Jarnoc36bbb22010-02-06 17:02:45 +0100315 if (do_translate_address(arg2, 1) == env->lladdr) { \
Aurelien Jarnoe7139c42009-11-30 15:39:54 +0100316 tmp = do_##ld_insn(arg2, mem_idx); \
317 if (tmp == env->llval) { \
318 do_##st_insn(arg2, arg1, mem_idx); \
319 return 1; \
320 } \
321 } \
322 return 0; \
323}
324HELPER_ST_ATOMIC(sc, lw, sw, 0x3)
325#ifdef TARGET_MIPS64
326HELPER_ST_ATOMIC(scd, ld, sd, 0x7)
327#endif
328#undef HELPER_ST_ATOMIC
329#endif
330
thsc8c22272008-06-20 15:12:14 +0000331#ifdef TARGET_WORDS_BIGENDIAN
332#define GET_LMASK(v) ((v) & 3)
333#define GET_OFFSET(addr, offset) (addr + (offset))
334#else
335#define GET_LMASK(v) (((v) & 3) ^ 3)
336#define GET_OFFSET(addr, offset) (addr - (offset))
337#endif
338
aurel32d9bea112009-04-15 14:41:44 +0000339target_ulong helper_lwl(target_ulong arg1, target_ulong arg2, int mem_idx)
thsc8c22272008-06-20 15:12:14 +0000340{
341 target_ulong tmp;
342
Aurelien Jarno0ae43042009-11-30 15:32:47 +0100343 tmp = do_lbu(arg2, mem_idx);
aurel32d9bea112009-04-15 14:41:44 +0000344 arg1 = (arg1 & 0x00FFFFFF) | (tmp << 24);
thsc8c22272008-06-20 15:12:14 +0000345
aurel32d9bea112009-04-15 14:41:44 +0000346 if (GET_LMASK(arg2) <= 2) {
Aurelien Jarno0ae43042009-11-30 15:32:47 +0100347 tmp = do_lbu(GET_OFFSET(arg2, 1), mem_idx);
aurel32d9bea112009-04-15 14:41:44 +0000348 arg1 = (arg1 & 0xFF00FFFF) | (tmp << 16);
thsc8c22272008-06-20 15:12:14 +0000349 }
350
aurel32d9bea112009-04-15 14:41:44 +0000351 if (GET_LMASK(arg2) <= 1) {
Aurelien Jarno0ae43042009-11-30 15:32:47 +0100352 tmp = do_lbu(GET_OFFSET(arg2, 2), mem_idx);
aurel32d9bea112009-04-15 14:41:44 +0000353 arg1 = (arg1 & 0xFFFF00FF) | (tmp << 8);
thsc8c22272008-06-20 15:12:14 +0000354 }
355
aurel32d9bea112009-04-15 14:41:44 +0000356 if (GET_LMASK(arg2) == 0) {
Aurelien Jarno0ae43042009-11-30 15:32:47 +0100357 tmp = do_lbu(GET_OFFSET(arg2, 3), mem_idx);
aurel32d9bea112009-04-15 14:41:44 +0000358 arg1 = (arg1 & 0xFFFFFF00) | tmp;
thsc8c22272008-06-20 15:12:14 +0000359 }
aurel32d9bea112009-04-15 14:41:44 +0000360 return (int32_t)arg1;
thsc8c22272008-06-20 15:12:14 +0000361}
362
aurel32d9bea112009-04-15 14:41:44 +0000363target_ulong helper_lwr(target_ulong arg1, target_ulong arg2, int mem_idx)
thsc8c22272008-06-20 15:12:14 +0000364{
365 target_ulong tmp;
366
Aurelien Jarno0ae43042009-11-30 15:32:47 +0100367 tmp = do_lbu(arg2, mem_idx);
aurel32d9bea112009-04-15 14:41:44 +0000368 arg1 = (arg1 & 0xFFFFFF00) | tmp;
thsc8c22272008-06-20 15:12:14 +0000369
aurel32d9bea112009-04-15 14:41:44 +0000370 if (GET_LMASK(arg2) >= 1) {
Aurelien Jarno0ae43042009-11-30 15:32:47 +0100371 tmp = do_lbu(GET_OFFSET(arg2, -1), mem_idx);
aurel32d9bea112009-04-15 14:41:44 +0000372 arg1 = (arg1 & 0xFFFF00FF) | (tmp << 8);
thsc8c22272008-06-20 15:12:14 +0000373 }
374
aurel32d9bea112009-04-15 14:41:44 +0000375 if (GET_LMASK(arg2) >= 2) {
Aurelien Jarno0ae43042009-11-30 15:32:47 +0100376 tmp = do_lbu(GET_OFFSET(arg2, -2), mem_idx);
aurel32d9bea112009-04-15 14:41:44 +0000377 arg1 = (arg1 & 0xFF00FFFF) | (tmp << 16);
thsc8c22272008-06-20 15:12:14 +0000378 }
379
aurel32d9bea112009-04-15 14:41:44 +0000380 if (GET_LMASK(arg2) == 3) {
Aurelien Jarno0ae43042009-11-30 15:32:47 +0100381 tmp = do_lbu(GET_OFFSET(arg2, -3), mem_idx);
aurel32d9bea112009-04-15 14:41:44 +0000382 arg1 = (arg1 & 0x00FFFFFF) | (tmp << 24);
thsc8c22272008-06-20 15:12:14 +0000383 }
aurel32d9bea112009-04-15 14:41:44 +0000384 return (int32_t)arg1;
thsc8c22272008-06-20 15:12:14 +0000385}
386
aurel32d9bea112009-04-15 14:41:44 +0000387void helper_swl(target_ulong arg1, target_ulong arg2, int mem_idx)
thsc8c22272008-06-20 15:12:14 +0000388{
Aurelien Jarno0ae43042009-11-30 15:32:47 +0100389 do_sb(arg2, (uint8_t)(arg1 >> 24), mem_idx);
thsc8c22272008-06-20 15:12:14 +0000390
aurel32d9bea112009-04-15 14:41:44 +0000391 if (GET_LMASK(arg2) <= 2)
Aurelien Jarno0ae43042009-11-30 15:32:47 +0100392 do_sb(GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 16), mem_idx);
thsc8c22272008-06-20 15:12:14 +0000393
aurel32d9bea112009-04-15 14:41:44 +0000394 if (GET_LMASK(arg2) <= 1)
Aurelien Jarno0ae43042009-11-30 15:32:47 +0100395 do_sb(GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 8), mem_idx);
thsc8c22272008-06-20 15:12:14 +0000396
aurel32d9bea112009-04-15 14:41:44 +0000397 if (GET_LMASK(arg2) == 0)
Aurelien Jarno0ae43042009-11-30 15:32:47 +0100398 do_sb(GET_OFFSET(arg2, 3), (uint8_t)arg1, mem_idx);
thsc8c22272008-06-20 15:12:14 +0000399}
400
aurel32d9bea112009-04-15 14:41:44 +0000401void helper_swr(target_ulong arg1, target_ulong arg2, int mem_idx)
thsc8c22272008-06-20 15:12:14 +0000402{
Aurelien Jarno0ae43042009-11-30 15:32:47 +0100403 do_sb(arg2, (uint8_t)arg1, mem_idx);
thsc8c22272008-06-20 15:12:14 +0000404
aurel32d9bea112009-04-15 14:41:44 +0000405 if (GET_LMASK(arg2) >= 1)
Aurelien Jarno0ae43042009-11-30 15:32:47 +0100406 do_sb(GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8), mem_idx);
thsc8c22272008-06-20 15:12:14 +0000407
aurel32d9bea112009-04-15 14:41:44 +0000408 if (GET_LMASK(arg2) >= 2)
Aurelien Jarno0ae43042009-11-30 15:32:47 +0100409 do_sb(GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16), mem_idx);
thsc8c22272008-06-20 15:12:14 +0000410
aurel32d9bea112009-04-15 14:41:44 +0000411 if (GET_LMASK(arg2) == 3)
Aurelien Jarno0ae43042009-11-30 15:32:47 +0100412 do_sb(GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24), mem_idx);
thsc8c22272008-06-20 15:12:14 +0000413}
414
415#if defined(TARGET_MIPS64)
416/* "half" load and stores. We must do the memory access inline,
417 or fault handling won't work. */
418
419#ifdef TARGET_WORDS_BIGENDIAN
420#define GET_LMASK64(v) ((v) & 7)
421#else
422#define GET_LMASK64(v) (((v) & 7) ^ 7)
423#endif
424
aurel32d9bea112009-04-15 14:41:44 +0000425target_ulong helper_ldl(target_ulong arg1, target_ulong arg2, int mem_idx)
thsc8c22272008-06-20 15:12:14 +0000426{
427 uint64_t tmp;
428
Aurelien Jarno0ae43042009-11-30 15:32:47 +0100429 tmp = do_lbu(arg2, mem_idx);
aurel32d9bea112009-04-15 14:41:44 +0000430 arg1 = (arg1 & 0x00FFFFFFFFFFFFFFULL) | (tmp << 56);
thsc8c22272008-06-20 15:12:14 +0000431
aurel32d9bea112009-04-15 14:41:44 +0000432 if (GET_LMASK64(arg2) <= 6) {
Aurelien Jarno0ae43042009-11-30 15:32:47 +0100433 tmp = do_lbu(GET_OFFSET(arg2, 1), mem_idx);
aurel32d9bea112009-04-15 14:41:44 +0000434 arg1 = (arg1 & 0xFF00FFFFFFFFFFFFULL) | (tmp << 48);
thsc8c22272008-06-20 15:12:14 +0000435 }
436
aurel32d9bea112009-04-15 14:41:44 +0000437 if (GET_LMASK64(arg2) <= 5) {
Aurelien Jarno0ae43042009-11-30 15:32:47 +0100438 tmp = do_lbu(GET_OFFSET(arg2, 2), mem_idx);
aurel32d9bea112009-04-15 14:41:44 +0000439 arg1 = (arg1 & 0xFFFF00FFFFFFFFFFULL) | (tmp << 40);
thsc8c22272008-06-20 15:12:14 +0000440 }
441
aurel32d9bea112009-04-15 14:41:44 +0000442 if (GET_LMASK64(arg2) <= 4) {
Aurelien Jarno0ae43042009-11-30 15:32:47 +0100443 tmp = do_lbu(GET_OFFSET(arg2, 3), mem_idx);
aurel32d9bea112009-04-15 14:41:44 +0000444 arg1 = (arg1 & 0xFFFFFF00FFFFFFFFULL) | (tmp << 32);
thsc8c22272008-06-20 15:12:14 +0000445 }
446
aurel32d9bea112009-04-15 14:41:44 +0000447 if (GET_LMASK64(arg2) <= 3) {
Aurelien Jarno0ae43042009-11-30 15:32:47 +0100448 tmp = do_lbu(GET_OFFSET(arg2, 4), mem_idx);
aurel32d9bea112009-04-15 14:41:44 +0000449 arg1 = (arg1 & 0xFFFFFFFF00FFFFFFULL) | (tmp << 24);
thsc8c22272008-06-20 15:12:14 +0000450 }
451
aurel32d9bea112009-04-15 14:41:44 +0000452 if (GET_LMASK64(arg2) <= 2) {
Aurelien Jarno0ae43042009-11-30 15:32:47 +0100453 tmp = do_lbu(GET_OFFSET(arg2, 5), mem_idx);
aurel32d9bea112009-04-15 14:41:44 +0000454 arg1 = (arg1 & 0xFFFFFFFFFF00FFFFULL) | (tmp << 16);
thsc8c22272008-06-20 15:12:14 +0000455 }
456
aurel32d9bea112009-04-15 14:41:44 +0000457 if (GET_LMASK64(arg2) <= 1) {
Aurelien Jarno0ae43042009-11-30 15:32:47 +0100458 tmp = do_lbu(GET_OFFSET(arg2, 6), mem_idx);
aurel32d9bea112009-04-15 14:41:44 +0000459 arg1 = (arg1 & 0xFFFFFFFFFFFF00FFULL) | (tmp << 8);
thsc8c22272008-06-20 15:12:14 +0000460 }
461
aurel32d9bea112009-04-15 14:41:44 +0000462 if (GET_LMASK64(arg2) == 0) {
Aurelien Jarno0ae43042009-11-30 15:32:47 +0100463 tmp = do_lbu(GET_OFFSET(arg2, 7), mem_idx);
aurel32d9bea112009-04-15 14:41:44 +0000464 arg1 = (arg1 & 0xFFFFFFFFFFFFFF00ULL) | tmp;
thsc8c22272008-06-20 15:12:14 +0000465 }
thsbe24bb42008-06-23 12:57:09 +0000466
aurel32d9bea112009-04-15 14:41:44 +0000467 return arg1;
thsc8c22272008-06-20 15:12:14 +0000468}
469
aurel32d9bea112009-04-15 14:41:44 +0000470target_ulong helper_ldr(target_ulong arg1, target_ulong arg2, int mem_idx)
thsc8c22272008-06-20 15:12:14 +0000471{
472 uint64_t tmp;
473
Aurelien Jarno0ae43042009-11-30 15:32:47 +0100474 tmp = do_lbu(arg2, mem_idx);
aurel32d9bea112009-04-15 14:41:44 +0000475 arg1 = (arg1 & 0xFFFFFFFFFFFFFF00ULL) | tmp;
thsc8c22272008-06-20 15:12:14 +0000476
aurel32d9bea112009-04-15 14:41:44 +0000477 if (GET_LMASK64(arg2) >= 1) {
Aurelien Jarno0ae43042009-11-30 15:32:47 +0100478 tmp = do_lbu(GET_OFFSET(arg2, -1), mem_idx);
aurel32d9bea112009-04-15 14:41:44 +0000479 arg1 = (arg1 & 0xFFFFFFFFFFFF00FFULL) | (tmp << 8);
thsc8c22272008-06-20 15:12:14 +0000480 }
481
aurel32d9bea112009-04-15 14:41:44 +0000482 if (GET_LMASK64(arg2) >= 2) {
Aurelien Jarno0ae43042009-11-30 15:32:47 +0100483 tmp = do_lbu(GET_OFFSET(arg2, -2), mem_idx);
aurel32d9bea112009-04-15 14:41:44 +0000484 arg1 = (arg1 & 0xFFFFFFFFFF00FFFFULL) | (tmp << 16);
thsc8c22272008-06-20 15:12:14 +0000485 }
486
aurel32d9bea112009-04-15 14:41:44 +0000487 if (GET_LMASK64(arg2) >= 3) {
Aurelien Jarno0ae43042009-11-30 15:32:47 +0100488 tmp = do_lbu(GET_OFFSET(arg2, -3), mem_idx);
aurel32d9bea112009-04-15 14:41:44 +0000489 arg1 = (arg1 & 0xFFFFFFFF00FFFFFFULL) | (tmp << 24);
thsc8c22272008-06-20 15:12:14 +0000490 }
491
aurel32d9bea112009-04-15 14:41:44 +0000492 if (GET_LMASK64(arg2) >= 4) {
Aurelien Jarno0ae43042009-11-30 15:32:47 +0100493 tmp = do_lbu(GET_OFFSET(arg2, -4), mem_idx);
aurel32d9bea112009-04-15 14:41:44 +0000494 arg1 = (arg1 & 0xFFFFFF00FFFFFFFFULL) | (tmp << 32);
thsc8c22272008-06-20 15:12:14 +0000495 }
496
aurel32d9bea112009-04-15 14:41:44 +0000497 if (GET_LMASK64(arg2) >= 5) {
Aurelien Jarno0ae43042009-11-30 15:32:47 +0100498 tmp = do_lbu(GET_OFFSET(arg2, -5), mem_idx);
aurel32d9bea112009-04-15 14:41:44 +0000499 arg1 = (arg1 & 0xFFFF00FFFFFFFFFFULL) | (tmp << 40);
thsc8c22272008-06-20 15:12:14 +0000500 }
501
aurel32d9bea112009-04-15 14:41:44 +0000502 if (GET_LMASK64(arg2) >= 6) {
Aurelien Jarno0ae43042009-11-30 15:32:47 +0100503 tmp = do_lbu(GET_OFFSET(arg2, -6), mem_idx);
aurel32d9bea112009-04-15 14:41:44 +0000504 arg1 = (arg1 & 0xFF00FFFFFFFFFFFFULL) | (tmp << 48);
thsc8c22272008-06-20 15:12:14 +0000505 }
506
aurel32d9bea112009-04-15 14:41:44 +0000507 if (GET_LMASK64(arg2) == 7) {
Aurelien Jarno0ae43042009-11-30 15:32:47 +0100508 tmp = do_lbu(GET_OFFSET(arg2, -7), mem_idx);
aurel32d9bea112009-04-15 14:41:44 +0000509 arg1 = (arg1 & 0x00FFFFFFFFFFFFFFULL) | (tmp << 56);
thsc8c22272008-06-20 15:12:14 +0000510 }
thsbe24bb42008-06-23 12:57:09 +0000511
aurel32d9bea112009-04-15 14:41:44 +0000512 return arg1;
thsc8c22272008-06-20 15:12:14 +0000513}
514
aurel32d9bea112009-04-15 14:41:44 +0000515void helper_sdl(target_ulong arg1, target_ulong arg2, int mem_idx)
thsc8c22272008-06-20 15:12:14 +0000516{
Aurelien Jarno0ae43042009-11-30 15:32:47 +0100517 do_sb(arg2, (uint8_t)(arg1 >> 56), mem_idx);
thsc8c22272008-06-20 15:12:14 +0000518
aurel32d9bea112009-04-15 14:41:44 +0000519 if (GET_LMASK64(arg2) <= 6)
Aurelien Jarno0ae43042009-11-30 15:32:47 +0100520 do_sb(GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 48), mem_idx);
thsc8c22272008-06-20 15:12:14 +0000521
aurel32d9bea112009-04-15 14:41:44 +0000522 if (GET_LMASK64(arg2) <= 5)
Aurelien Jarno0ae43042009-11-30 15:32:47 +0100523 do_sb(GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 40), mem_idx);
thsc8c22272008-06-20 15:12:14 +0000524
aurel32d9bea112009-04-15 14:41:44 +0000525 if (GET_LMASK64(arg2) <= 4)
Aurelien Jarno0ae43042009-11-30 15:32:47 +0100526 do_sb(GET_OFFSET(arg2, 3), (uint8_t)(arg1 >> 32), mem_idx);
thsc8c22272008-06-20 15:12:14 +0000527
aurel32d9bea112009-04-15 14:41:44 +0000528 if (GET_LMASK64(arg2) <= 3)
Aurelien Jarno0ae43042009-11-30 15:32:47 +0100529 do_sb(GET_OFFSET(arg2, 4), (uint8_t)(arg1 >> 24), mem_idx);
thsc8c22272008-06-20 15:12:14 +0000530
aurel32d9bea112009-04-15 14:41:44 +0000531 if (GET_LMASK64(arg2) <= 2)
Aurelien Jarno0ae43042009-11-30 15:32:47 +0100532 do_sb(GET_OFFSET(arg2, 5), (uint8_t)(arg1 >> 16), mem_idx);
thsc8c22272008-06-20 15:12:14 +0000533
aurel32d9bea112009-04-15 14:41:44 +0000534 if (GET_LMASK64(arg2) <= 1)
Aurelien Jarno0ae43042009-11-30 15:32:47 +0100535 do_sb(GET_OFFSET(arg2, 6), (uint8_t)(arg1 >> 8), mem_idx);
thsc8c22272008-06-20 15:12:14 +0000536
aurel32d9bea112009-04-15 14:41:44 +0000537 if (GET_LMASK64(arg2) <= 0)
Aurelien Jarno0ae43042009-11-30 15:32:47 +0100538 do_sb(GET_OFFSET(arg2, 7), (uint8_t)arg1, mem_idx);
thsc8c22272008-06-20 15:12:14 +0000539}
540
aurel32d9bea112009-04-15 14:41:44 +0000541void helper_sdr(target_ulong arg1, target_ulong arg2, int mem_idx)
thsc8c22272008-06-20 15:12:14 +0000542{
Aurelien Jarno0ae43042009-11-30 15:32:47 +0100543 do_sb(arg2, (uint8_t)arg1, mem_idx);
thsc8c22272008-06-20 15:12:14 +0000544
aurel32d9bea112009-04-15 14:41:44 +0000545 if (GET_LMASK64(arg2) >= 1)
Aurelien Jarno0ae43042009-11-30 15:32:47 +0100546 do_sb(GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8), mem_idx);
thsc8c22272008-06-20 15:12:14 +0000547
aurel32d9bea112009-04-15 14:41:44 +0000548 if (GET_LMASK64(arg2) >= 2)
Aurelien Jarno0ae43042009-11-30 15:32:47 +0100549 do_sb(GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16), mem_idx);
thsc8c22272008-06-20 15:12:14 +0000550
aurel32d9bea112009-04-15 14:41:44 +0000551 if (GET_LMASK64(arg2) >= 3)
Aurelien Jarno0ae43042009-11-30 15:32:47 +0100552 do_sb(GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24), mem_idx);
thsc8c22272008-06-20 15:12:14 +0000553
aurel32d9bea112009-04-15 14:41:44 +0000554 if (GET_LMASK64(arg2) >= 4)
Aurelien Jarno0ae43042009-11-30 15:32:47 +0100555 do_sb(GET_OFFSET(arg2, -4), (uint8_t)(arg1 >> 32), mem_idx);
thsc8c22272008-06-20 15:12:14 +0000556
aurel32d9bea112009-04-15 14:41:44 +0000557 if (GET_LMASK64(arg2) >= 5)
Aurelien Jarno0ae43042009-11-30 15:32:47 +0100558 do_sb(GET_OFFSET(arg2, -5), (uint8_t)(arg1 >> 40), mem_idx);
thsc8c22272008-06-20 15:12:14 +0000559
aurel32d9bea112009-04-15 14:41:44 +0000560 if (GET_LMASK64(arg2) >= 6)
Aurelien Jarno0ae43042009-11-30 15:32:47 +0100561 do_sb(GET_OFFSET(arg2, -6), (uint8_t)(arg1 >> 48), mem_idx);
thsc8c22272008-06-20 15:12:14 +0000562
aurel32d9bea112009-04-15 14:41:44 +0000563 if (GET_LMASK64(arg2) == 7)
Aurelien Jarno0ae43042009-11-30 15:32:47 +0100564 do_sb(GET_OFFSET(arg2, -7), (uint8_t)(arg1 >> 56), mem_idx);
thsc8c22272008-06-20 15:12:14 +0000565}
566#endif /* TARGET_MIPS64 */
567
ths0eaef5a2008-07-23 16:14:22 +0000568#ifndef CONFIG_USER_ONLY
bellard6af0bf92005-07-02 14:58:51 +0000569/* CP0 helpers */
aurel32c01fccd2009-03-08 00:06:01 +0000570target_ulong helper_mfc0_mvpcontrol (void)
thsf1aa6322008-06-09 07:13:38 +0000571{
thsbe24bb42008-06-23 12:57:09 +0000572 return env->mvp->CP0_MVPControl;
thsf1aa6322008-06-09 07:13:38 +0000573}
574
aurel32c01fccd2009-03-08 00:06:01 +0000575target_ulong helper_mfc0_mvpconf0 (void)
thsf1aa6322008-06-09 07:13:38 +0000576{
thsbe24bb42008-06-23 12:57:09 +0000577 return env->mvp->CP0_MVPConf0;
thsf1aa6322008-06-09 07:13:38 +0000578}
579
aurel32c01fccd2009-03-08 00:06:01 +0000580target_ulong helper_mfc0_mvpconf1 (void)
thsf1aa6322008-06-09 07:13:38 +0000581{
thsbe24bb42008-06-23 12:57:09 +0000582 return env->mvp->CP0_MVPConf1;
thsf1aa6322008-06-09 07:13:38 +0000583}
584
aurel32c01fccd2009-03-08 00:06:01 +0000585target_ulong helper_mfc0_random (void)
bellard6af0bf92005-07-02 14:58:51 +0000586{
thsbe24bb42008-06-23 12:57:09 +0000587 return (int32_t)cpu_mips_get_random(env);
ths873eb012006-12-06 17:59:07 +0000588}
bellard6af0bf92005-07-02 14:58:51 +0000589
aurel32c01fccd2009-03-08 00:06:01 +0000590target_ulong helper_mfc0_tcstatus (void)
thsf1aa6322008-06-09 07:13:38 +0000591{
thsb5dc7732008-06-27 10:02:35 +0000592 return env->active_tc.CP0_TCStatus;
thsf1aa6322008-06-09 07:13:38 +0000593}
594
aurel32c01fccd2009-03-08 00:06:01 +0000595target_ulong helper_mftc0_tcstatus(void)
thsf1aa6322008-06-09 07:13:38 +0000596{
597 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
598
thsb5dc7732008-06-27 10:02:35 +0000599 if (other_tc == env->current_tc)
600 return env->active_tc.CP0_TCStatus;
601 else
602 return env->tcs[other_tc].CP0_TCStatus;
thsf1aa6322008-06-09 07:13:38 +0000603}
604
aurel32c01fccd2009-03-08 00:06:01 +0000605target_ulong helper_mfc0_tcbind (void)
thsf1aa6322008-06-09 07:13:38 +0000606{
thsb5dc7732008-06-27 10:02:35 +0000607 return env->active_tc.CP0_TCBind;
thsf1aa6322008-06-09 07:13:38 +0000608}
609
aurel32c01fccd2009-03-08 00:06:01 +0000610target_ulong helper_mftc0_tcbind(void)
thsf1aa6322008-06-09 07:13:38 +0000611{
612 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
613
thsb5dc7732008-06-27 10:02:35 +0000614 if (other_tc == env->current_tc)
615 return env->active_tc.CP0_TCBind;
616 else
617 return env->tcs[other_tc].CP0_TCBind;
thsf1aa6322008-06-09 07:13:38 +0000618}
619
aurel32c01fccd2009-03-08 00:06:01 +0000620target_ulong helper_mfc0_tcrestart (void)
thsf1aa6322008-06-09 07:13:38 +0000621{
thsb5dc7732008-06-27 10:02:35 +0000622 return env->active_tc.PC;
thsf1aa6322008-06-09 07:13:38 +0000623}
624
aurel32c01fccd2009-03-08 00:06:01 +0000625target_ulong helper_mftc0_tcrestart(void)
thsf1aa6322008-06-09 07:13:38 +0000626{
627 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
628
thsb5dc7732008-06-27 10:02:35 +0000629 if (other_tc == env->current_tc)
630 return env->active_tc.PC;
631 else
632 return env->tcs[other_tc].PC;
thsf1aa6322008-06-09 07:13:38 +0000633}
634
aurel32c01fccd2009-03-08 00:06:01 +0000635target_ulong helper_mfc0_tchalt (void)
thsf1aa6322008-06-09 07:13:38 +0000636{
thsb5dc7732008-06-27 10:02:35 +0000637 return env->active_tc.CP0_TCHalt;
thsf1aa6322008-06-09 07:13:38 +0000638}
639
aurel32c01fccd2009-03-08 00:06:01 +0000640target_ulong helper_mftc0_tchalt(void)
thsf1aa6322008-06-09 07:13:38 +0000641{
642 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
643
thsb5dc7732008-06-27 10:02:35 +0000644 if (other_tc == env->current_tc)
645 return env->active_tc.CP0_TCHalt;
646 else
647 return env->tcs[other_tc].CP0_TCHalt;
thsf1aa6322008-06-09 07:13:38 +0000648}
649
aurel32c01fccd2009-03-08 00:06:01 +0000650target_ulong helper_mfc0_tccontext (void)
thsf1aa6322008-06-09 07:13:38 +0000651{
thsb5dc7732008-06-27 10:02:35 +0000652 return env->active_tc.CP0_TCContext;
thsf1aa6322008-06-09 07:13:38 +0000653}
654
aurel32c01fccd2009-03-08 00:06:01 +0000655target_ulong helper_mftc0_tccontext(void)
thsf1aa6322008-06-09 07:13:38 +0000656{
657 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
658
thsb5dc7732008-06-27 10:02:35 +0000659 if (other_tc == env->current_tc)
660 return env->active_tc.CP0_TCContext;
661 else
662 return env->tcs[other_tc].CP0_TCContext;
thsf1aa6322008-06-09 07:13:38 +0000663}
664
aurel32c01fccd2009-03-08 00:06:01 +0000665target_ulong helper_mfc0_tcschedule (void)
thsf1aa6322008-06-09 07:13:38 +0000666{
thsb5dc7732008-06-27 10:02:35 +0000667 return env->active_tc.CP0_TCSchedule;
thsf1aa6322008-06-09 07:13:38 +0000668}
669
aurel32c01fccd2009-03-08 00:06:01 +0000670target_ulong helper_mftc0_tcschedule(void)
thsf1aa6322008-06-09 07:13:38 +0000671{
672 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
673
thsb5dc7732008-06-27 10:02:35 +0000674 if (other_tc == env->current_tc)
675 return env->active_tc.CP0_TCSchedule;
676 else
677 return env->tcs[other_tc].CP0_TCSchedule;
thsf1aa6322008-06-09 07:13:38 +0000678}
679
aurel32c01fccd2009-03-08 00:06:01 +0000680target_ulong helper_mfc0_tcschefback (void)
thsf1aa6322008-06-09 07:13:38 +0000681{
thsb5dc7732008-06-27 10:02:35 +0000682 return env->active_tc.CP0_TCScheFBack;
thsf1aa6322008-06-09 07:13:38 +0000683}
684
aurel32c01fccd2009-03-08 00:06:01 +0000685target_ulong helper_mftc0_tcschefback(void)
thsf1aa6322008-06-09 07:13:38 +0000686{
687 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
688
thsb5dc7732008-06-27 10:02:35 +0000689 if (other_tc == env->current_tc)
690 return env->active_tc.CP0_TCScheFBack;
691 else
692 return env->tcs[other_tc].CP0_TCScheFBack;
thsf1aa6322008-06-09 07:13:38 +0000693}
694
aurel32c01fccd2009-03-08 00:06:01 +0000695target_ulong helper_mfc0_count (void)
ths873eb012006-12-06 17:59:07 +0000696{
thsbe24bb42008-06-23 12:57:09 +0000697 return (int32_t)cpu_mips_get_count(env);
bellard6af0bf92005-07-02 14:58:51 +0000698}
699
aurel32c01fccd2009-03-08 00:06:01 +0000700target_ulong helper_mftc0_entryhi(void)
thsf1aa6322008-06-09 07:13:38 +0000701{
702 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
thsb5dc7732008-06-27 10:02:35 +0000703 int32_t tcstatus;
thsf1aa6322008-06-09 07:13:38 +0000704
thsb5dc7732008-06-27 10:02:35 +0000705 if (other_tc == env->current_tc)
706 tcstatus = env->active_tc.CP0_TCStatus;
707 else
708 tcstatus = env->tcs[other_tc].CP0_TCStatus;
709
710 return (env->CP0_EntryHi & ~0xff) | (tcstatus & 0xff);
thsf1aa6322008-06-09 07:13:38 +0000711}
712
aurel32c01fccd2009-03-08 00:06:01 +0000713target_ulong helper_mftc0_status(void)
thsf1aa6322008-06-09 07:13:38 +0000714{
715 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
ths1a3fd9c2008-06-24 21:58:35 +0000716 target_ulong t0;
thsb5dc7732008-06-27 10:02:35 +0000717 int32_t tcstatus;
718
719 if (other_tc == env->current_tc)
720 tcstatus = env->active_tc.CP0_TCStatus;
721 else
722 tcstatus = env->tcs[other_tc].CP0_TCStatus;
thsf1aa6322008-06-09 07:13:38 +0000723
thsbe24bb42008-06-23 12:57:09 +0000724 t0 = env->CP0_Status & ~0xf1000018;
725 t0 |= tcstatus & (0xf << CP0TCSt_TCU0);
726 t0 |= (tcstatus & (1 << CP0TCSt_TMX)) >> (CP0TCSt_TMX - CP0St_MX);
727 t0 |= (tcstatus & (0x3 << CP0TCSt_TKSU)) >> (CP0TCSt_TKSU - CP0St_KSU);
728
729 return t0;
thsf1aa6322008-06-09 07:13:38 +0000730}
731
aurel32c01fccd2009-03-08 00:06:01 +0000732target_ulong helper_mfc0_lladdr (void)
thsf1aa6322008-06-09 07:13:38 +0000733{
Aurelien Jarno2a6e32d2009-11-22 13:22:54 +0100734 return (int32_t)(env->lladdr >> env->CP0_LLAddr_shift);
thsf1aa6322008-06-09 07:13:38 +0000735}
736
aurel32c01fccd2009-03-08 00:06:01 +0000737target_ulong helper_mfc0_watchlo (uint32_t sel)
thsf1aa6322008-06-09 07:13:38 +0000738{
thsbe24bb42008-06-23 12:57:09 +0000739 return (int32_t)env->CP0_WatchLo[sel];
thsf1aa6322008-06-09 07:13:38 +0000740}
741
aurel32c01fccd2009-03-08 00:06:01 +0000742target_ulong helper_mfc0_watchhi (uint32_t sel)
thsf1aa6322008-06-09 07:13:38 +0000743{
thsbe24bb42008-06-23 12:57:09 +0000744 return env->CP0_WatchHi[sel];
thsf1aa6322008-06-09 07:13:38 +0000745}
746
aurel32c01fccd2009-03-08 00:06:01 +0000747target_ulong helper_mfc0_debug (void)
thsf1aa6322008-06-09 07:13:38 +0000748{
ths1a3fd9c2008-06-24 21:58:35 +0000749 target_ulong t0 = env->CP0_Debug;
thsf1aa6322008-06-09 07:13:38 +0000750 if (env->hflags & MIPS_HFLAG_DM)
thsbe24bb42008-06-23 12:57:09 +0000751 t0 |= 1 << CP0DB_DM;
752
753 return t0;
thsf1aa6322008-06-09 07:13:38 +0000754}
755
aurel32c01fccd2009-03-08 00:06:01 +0000756target_ulong helper_mftc0_debug(void)
thsf1aa6322008-06-09 07:13:38 +0000757{
758 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
thsb5dc7732008-06-27 10:02:35 +0000759 int32_t tcstatus;
760
761 if (other_tc == env->current_tc)
762 tcstatus = env->active_tc.CP0_Debug_tcstatus;
763 else
764 tcstatus = env->tcs[other_tc].CP0_Debug_tcstatus;
thsf1aa6322008-06-09 07:13:38 +0000765
766 /* XXX: Might be wrong, check with EJTAG spec. */
thsbe24bb42008-06-23 12:57:09 +0000767 return (env->CP0_Debug & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
thsb5dc7732008-06-27 10:02:35 +0000768 (tcstatus & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
thsf1aa6322008-06-09 07:13:38 +0000769}
770
771#if defined(TARGET_MIPS64)
aurel32c01fccd2009-03-08 00:06:01 +0000772target_ulong helper_dmfc0_tcrestart (void)
thsf1aa6322008-06-09 07:13:38 +0000773{
thsb5dc7732008-06-27 10:02:35 +0000774 return env->active_tc.PC;
thsf1aa6322008-06-09 07:13:38 +0000775}
776
aurel32c01fccd2009-03-08 00:06:01 +0000777target_ulong helper_dmfc0_tchalt (void)
thsf1aa6322008-06-09 07:13:38 +0000778{
thsb5dc7732008-06-27 10:02:35 +0000779 return env->active_tc.CP0_TCHalt;
thsf1aa6322008-06-09 07:13:38 +0000780}
781
aurel32c01fccd2009-03-08 00:06:01 +0000782target_ulong helper_dmfc0_tccontext (void)
thsf1aa6322008-06-09 07:13:38 +0000783{
thsb5dc7732008-06-27 10:02:35 +0000784 return env->active_tc.CP0_TCContext;
thsf1aa6322008-06-09 07:13:38 +0000785}
786
aurel32c01fccd2009-03-08 00:06:01 +0000787target_ulong helper_dmfc0_tcschedule (void)
thsf1aa6322008-06-09 07:13:38 +0000788{
thsb5dc7732008-06-27 10:02:35 +0000789 return env->active_tc.CP0_TCSchedule;
thsf1aa6322008-06-09 07:13:38 +0000790}
791
aurel32c01fccd2009-03-08 00:06:01 +0000792target_ulong helper_dmfc0_tcschefback (void)
thsf1aa6322008-06-09 07:13:38 +0000793{
thsb5dc7732008-06-27 10:02:35 +0000794 return env->active_tc.CP0_TCScheFBack;
thsf1aa6322008-06-09 07:13:38 +0000795}
796
aurel32c01fccd2009-03-08 00:06:01 +0000797target_ulong helper_dmfc0_lladdr (void)
thsf1aa6322008-06-09 07:13:38 +0000798{
Aurelien Jarno2a6e32d2009-11-22 13:22:54 +0100799 return env->lladdr >> env->CP0_LLAddr_shift;
thsf1aa6322008-06-09 07:13:38 +0000800}
801
aurel32c01fccd2009-03-08 00:06:01 +0000802target_ulong helper_dmfc0_watchlo (uint32_t sel)
thsf1aa6322008-06-09 07:13:38 +0000803{
thsbe24bb42008-06-23 12:57:09 +0000804 return env->CP0_WatchLo[sel];
thsf1aa6322008-06-09 07:13:38 +0000805}
806#endif /* TARGET_MIPS64 */
807
aurel32d9bea112009-04-15 14:41:44 +0000808void helper_mtc0_index (target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +0000809{
810 int num = 1;
811 unsigned int tmp = env->tlb->nb_tlb;
812
813 do {
814 tmp >>= 1;
815 num <<= 1;
816 } while (tmp);
aurel32d9bea112009-04-15 14:41:44 +0000817 env->CP0_Index = (env->CP0_Index & 0x80000000) | (arg1 & (num - 1));
thsf1aa6322008-06-09 07:13:38 +0000818}
819
aurel32d9bea112009-04-15 14:41:44 +0000820void helper_mtc0_mvpcontrol (target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +0000821{
822 uint32_t mask = 0;
823 uint32_t newval;
824
825 if (env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP))
826 mask |= (1 << CP0MVPCo_CPA) | (1 << CP0MVPCo_VPC) |
827 (1 << CP0MVPCo_EVP);
828 if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
829 mask |= (1 << CP0MVPCo_STLB);
aurel32d9bea112009-04-15 14:41:44 +0000830 newval = (env->mvp->CP0_MVPControl & ~mask) | (arg1 & mask);
thsf1aa6322008-06-09 07:13:38 +0000831
832 // TODO: Enable/disable shared TLB, enable/disable VPEs.
833
834 env->mvp->CP0_MVPControl = newval;
835}
836
aurel32d9bea112009-04-15 14:41:44 +0000837void helper_mtc0_vpecontrol (target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +0000838{
839 uint32_t mask;
840 uint32_t newval;
841
842 mask = (1 << CP0VPECo_YSI) | (1 << CP0VPECo_GSI) |
843 (1 << CP0VPECo_TE) | (0xff << CP0VPECo_TargTC);
aurel32d9bea112009-04-15 14:41:44 +0000844 newval = (env->CP0_VPEControl & ~mask) | (arg1 & mask);
thsf1aa6322008-06-09 07:13:38 +0000845
846 /* Yield scheduler intercept not implemented. */
847 /* Gating storage scheduler intercept not implemented. */
848
849 // TODO: Enable/disable TCs.
850
851 env->CP0_VPEControl = newval;
852}
853
aurel32d9bea112009-04-15 14:41:44 +0000854void helper_mtc0_vpeconf0 (target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +0000855{
856 uint32_t mask = 0;
857 uint32_t newval;
858
859 if (env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) {
860 if (env->CP0_VPEConf0 & (1 << CP0VPEC0_VPA))
861 mask |= (0xff << CP0VPEC0_XTC);
862 mask |= (1 << CP0VPEC0_MVP) | (1 << CP0VPEC0_VPA);
863 }
aurel32d9bea112009-04-15 14:41:44 +0000864 newval = (env->CP0_VPEConf0 & ~mask) | (arg1 & mask);
thsf1aa6322008-06-09 07:13:38 +0000865
866 // TODO: TC exclusive handling due to ERL/EXL.
867
868 env->CP0_VPEConf0 = newval;
869}
870
aurel32d9bea112009-04-15 14:41:44 +0000871void helper_mtc0_vpeconf1 (target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +0000872{
873 uint32_t mask = 0;
874 uint32_t newval;
875
876 if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
877 mask |= (0xff << CP0VPEC1_NCX) | (0xff << CP0VPEC1_NCP2) |
878 (0xff << CP0VPEC1_NCP1);
aurel32d9bea112009-04-15 14:41:44 +0000879 newval = (env->CP0_VPEConf1 & ~mask) | (arg1 & mask);
thsf1aa6322008-06-09 07:13:38 +0000880
881 /* UDI not implemented. */
882 /* CP2 not implemented. */
883
884 // TODO: Handle FPU (CP1) binding.
885
886 env->CP0_VPEConf1 = newval;
887}
888
aurel32d9bea112009-04-15 14:41:44 +0000889void helper_mtc0_yqmask (target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +0000890{
891 /* Yield qualifier inputs not implemented. */
892 env->CP0_YQMask = 0x00000000;
893}
894
aurel32d9bea112009-04-15 14:41:44 +0000895void helper_mtc0_vpeopt (target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +0000896{
aurel32d9bea112009-04-15 14:41:44 +0000897 env->CP0_VPEOpt = arg1 & 0x0000ffff;
thsf1aa6322008-06-09 07:13:38 +0000898}
899
aurel32d9bea112009-04-15 14:41:44 +0000900void helper_mtc0_entrylo0 (target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +0000901{
902 /* Large physaddr (PABITS) not implemented */
903 /* 1k pages not implemented */
aurel32d9bea112009-04-15 14:41:44 +0000904 env->CP0_EntryLo0 = arg1 & 0x3FFFFFFF;
thsf1aa6322008-06-09 07:13:38 +0000905}
906
aurel32d9bea112009-04-15 14:41:44 +0000907void helper_mtc0_tcstatus (target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +0000908{
909 uint32_t mask = env->CP0_TCStatus_rw_bitmask;
910 uint32_t newval;
911
aurel32d9bea112009-04-15 14:41:44 +0000912 newval = (env->active_tc.CP0_TCStatus & ~mask) | (arg1 & mask);
thsf1aa6322008-06-09 07:13:38 +0000913
914 // TODO: Sync with CP0_Status.
915
thsb5dc7732008-06-27 10:02:35 +0000916 env->active_tc.CP0_TCStatus = newval;
thsf1aa6322008-06-09 07:13:38 +0000917}
918
aurel32d9bea112009-04-15 14:41:44 +0000919void helper_mttc0_tcstatus (target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +0000920{
921 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
922
923 // TODO: Sync with CP0_Status.
924
thsb5dc7732008-06-27 10:02:35 +0000925 if (other_tc == env->current_tc)
aurel32d9bea112009-04-15 14:41:44 +0000926 env->active_tc.CP0_TCStatus = arg1;
thsb5dc7732008-06-27 10:02:35 +0000927 else
aurel32d9bea112009-04-15 14:41:44 +0000928 env->tcs[other_tc].CP0_TCStatus = arg1;
thsf1aa6322008-06-09 07:13:38 +0000929}
930
aurel32d9bea112009-04-15 14:41:44 +0000931void helper_mtc0_tcbind (target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +0000932{
933 uint32_t mask = (1 << CP0TCBd_TBE);
934 uint32_t newval;
935
936 if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
937 mask |= (1 << CP0TCBd_CurVPE);
aurel32d9bea112009-04-15 14:41:44 +0000938 newval = (env->active_tc.CP0_TCBind & ~mask) | (arg1 & mask);
thsb5dc7732008-06-27 10:02:35 +0000939 env->active_tc.CP0_TCBind = newval;
thsf1aa6322008-06-09 07:13:38 +0000940}
941
aurel32d9bea112009-04-15 14:41:44 +0000942void helper_mttc0_tcbind (target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +0000943{
944 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
945 uint32_t mask = (1 << CP0TCBd_TBE);
946 uint32_t newval;
947
948 if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
949 mask |= (1 << CP0TCBd_CurVPE);
thsb5dc7732008-06-27 10:02:35 +0000950 if (other_tc == env->current_tc) {
aurel32d9bea112009-04-15 14:41:44 +0000951 newval = (env->active_tc.CP0_TCBind & ~mask) | (arg1 & mask);
thsb5dc7732008-06-27 10:02:35 +0000952 env->active_tc.CP0_TCBind = newval;
953 } else {
aurel32d9bea112009-04-15 14:41:44 +0000954 newval = (env->tcs[other_tc].CP0_TCBind & ~mask) | (arg1 & mask);
thsb5dc7732008-06-27 10:02:35 +0000955 env->tcs[other_tc].CP0_TCBind = newval;
956 }
thsf1aa6322008-06-09 07:13:38 +0000957}
958
aurel32d9bea112009-04-15 14:41:44 +0000959void helper_mtc0_tcrestart (target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +0000960{
aurel32d9bea112009-04-15 14:41:44 +0000961 env->active_tc.PC = arg1;
thsb5dc7732008-06-27 10:02:35 +0000962 env->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
Aurelien Jarno5499b6f2009-11-22 13:08:14 +0100963 env->lladdr = 0ULL;
thsf1aa6322008-06-09 07:13:38 +0000964 /* MIPS16 not implemented. */
965}
966
aurel32d9bea112009-04-15 14:41:44 +0000967void helper_mttc0_tcrestart (target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +0000968{
969 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
970
thsb5dc7732008-06-27 10:02:35 +0000971 if (other_tc == env->current_tc) {
aurel32d9bea112009-04-15 14:41:44 +0000972 env->active_tc.PC = arg1;
thsb5dc7732008-06-27 10:02:35 +0000973 env->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
Aurelien Jarno5499b6f2009-11-22 13:08:14 +0100974 env->lladdr = 0ULL;
thsb5dc7732008-06-27 10:02:35 +0000975 /* MIPS16 not implemented. */
976 } else {
aurel32d9bea112009-04-15 14:41:44 +0000977 env->tcs[other_tc].PC = arg1;
thsb5dc7732008-06-27 10:02:35 +0000978 env->tcs[other_tc].CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
Aurelien Jarno5499b6f2009-11-22 13:08:14 +0100979 env->lladdr = 0ULL;
thsb5dc7732008-06-27 10:02:35 +0000980 /* MIPS16 not implemented. */
981 }
thsf1aa6322008-06-09 07:13:38 +0000982}
983
aurel32d9bea112009-04-15 14:41:44 +0000984void helper_mtc0_tchalt (target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +0000985{
aurel32d9bea112009-04-15 14:41:44 +0000986 env->active_tc.CP0_TCHalt = arg1 & 0x1;
thsf1aa6322008-06-09 07:13:38 +0000987
988 // TODO: Halt TC / Restart (if allocated+active) TC.
989}
990
aurel32d9bea112009-04-15 14:41:44 +0000991void helper_mttc0_tchalt (target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +0000992{
993 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
994
995 // TODO: Halt TC / Restart (if allocated+active) TC.
996
thsb5dc7732008-06-27 10:02:35 +0000997 if (other_tc == env->current_tc)
aurel32d9bea112009-04-15 14:41:44 +0000998 env->active_tc.CP0_TCHalt = arg1;
thsb5dc7732008-06-27 10:02:35 +0000999 else
aurel32d9bea112009-04-15 14:41:44 +00001000 env->tcs[other_tc].CP0_TCHalt = arg1;
thsf1aa6322008-06-09 07:13:38 +00001001}
1002
aurel32d9bea112009-04-15 14:41:44 +00001003void helper_mtc0_tccontext (target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001004{
aurel32d9bea112009-04-15 14:41:44 +00001005 env->active_tc.CP0_TCContext = arg1;
thsf1aa6322008-06-09 07:13:38 +00001006}
1007
aurel32d9bea112009-04-15 14:41:44 +00001008void helper_mttc0_tccontext (target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001009{
1010 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1011
thsb5dc7732008-06-27 10:02:35 +00001012 if (other_tc == env->current_tc)
aurel32d9bea112009-04-15 14:41:44 +00001013 env->active_tc.CP0_TCContext = arg1;
thsb5dc7732008-06-27 10:02:35 +00001014 else
aurel32d9bea112009-04-15 14:41:44 +00001015 env->tcs[other_tc].CP0_TCContext = arg1;
thsf1aa6322008-06-09 07:13:38 +00001016}
1017
aurel32d9bea112009-04-15 14:41:44 +00001018void helper_mtc0_tcschedule (target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001019{
aurel32d9bea112009-04-15 14:41:44 +00001020 env->active_tc.CP0_TCSchedule = arg1;
thsf1aa6322008-06-09 07:13:38 +00001021}
1022
aurel32d9bea112009-04-15 14:41:44 +00001023void helper_mttc0_tcschedule (target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001024{
1025 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1026
thsb5dc7732008-06-27 10:02:35 +00001027 if (other_tc == env->current_tc)
aurel32d9bea112009-04-15 14:41:44 +00001028 env->active_tc.CP0_TCSchedule = arg1;
thsb5dc7732008-06-27 10:02:35 +00001029 else
aurel32d9bea112009-04-15 14:41:44 +00001030 env->tcs[other_tc].CP0_TCSchedule = arg1;
thsf1aa6322008-06-09 07:13:38 +00001031}
1032
aurel32d9bea112009-04-15 14:41:44 +00001033void helper_mtc0_tcschefback (target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001034{
aurel32d9bea112009-04-15 14:41:44 +00001035 env->active_tc.CP0_TCScheFBack = arg1;
thsf1aa6322008-06-09 07:13:38 +00001036}
1037
aurel32d9bea112009-04-15 14:41:44 +00001038void helper_mttc0_tcschefback (target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001039{
1040 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1041
thsb5dc7732008-06-27 10:02:35 +00001042 if (other_tc == env->current_tc)
aurel32d9bea112009-04-15 14:41:44 +00001043 env->active_tc.CP0_TCScheFBack = arg1;
thsb5dc7732008-06-27 10:02:35 +00001044 else
aurel32d9bea112009-04-15 14:41:44 +00001045 env->tcs[other_tc].CP0_TCScheFBack = arg1;
thsf1aa6322008-06-09 07:13:38 +00001046}
1047
aurel32d9bea112009-04-15 14:41:44 +00001048void helper_mtc0_entrylo1 (target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001049{
1050 /* Large physaddr (PABITS) not implemented */
1051 /* 1k pages not implemented */
aurel32d9bea112009-04-15 14:41:44 +00001052 env->CP0_EntryLo1 = arg1 & 0x3FFFFFFF;
thsf1aa6322008-06-09 07:13:38 +00001053}
1054
aurel32d9bea112009-04-15 14:41:44 +00001055void helper_mtc0_context (target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001056{
aurel32d9bea112009-04-15 14:41:44 +00001057 env->CP0_Context = (env->CP0_Context & 0x007FFFFF) | (arg1 & ~0x007FFFFF);
thsf1aa6322008-06-09 07:13:38 +00001058}
1059
aurel32d9bea112009-04-15 14:41:44 +00001060void helper_mtc0_pagemask (target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001061{
1062 /* 1k pages not implemented */
aurel32d9bea112009-04-15 14:41:44 +00001063 env->CP0_PageMask = arg1 & (0x1FFFFFFF & (TARGET_PAGE_MASK << 1));
thsf1aa6322008-06-09 07:13:38 +00001064}
1065
aurel32d9bea112009-04-15 14:41:44 +00001066void helper_mtc0_pagegrain (target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001067{
1068 /* SmartMIPS not implemented */
1069 /* Large physaddr (PABITS) not implemented */
1070 /* 1k pages not implemented */
1071 env->CP0_PageGrain = 0;
1072}
1073
aurel32d9bea112009-04-15 14:41:44 +00001074void helper_mtc0_wired (target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001075{
aurel32d9bea112009-04-15 14:41:44 +00001076 env->CP0_Wired = arg1 % env->tlb->nb_tlb;
thsf1aa6322008-06-09 07:13:38 +00001077}
1078
aurel32d9bea112009-04-15 14:41:44 +00001079void helper_mtc0_srsconf0 (target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001080{
aurel32d9bea112009-04-15 14:41:44 +00001081 env->CP0_SRSConf0 |= arg1 & env->CP0_SRSConf0_rw_bitmask;
thsf1aa6322008-06-09 07:13:38 +00001082}
1083
aurel32d9bea112009-04-15 14:41:44 +00001084void helper_mtc0_srsconf1 (target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001085{
aurel32d9bea112009-04-15 14:41:44 +00001086 env->CP0_SRSConf1 |= arg1 & env->CP0_SRSConf1_rw_bitmask;
thsf1aa6322008-06-09 07:13:38 +00001087}
1088
aurel32d9bea112009-04-15 14:41:44 +00001089void helper_mtc0_srsconf2 (target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001090{
aurel32d9bea112009-04-15 14:41:44 +00001091 env->CP0_SRSConf2 |= arg1 & env->CP0_SRSConf2_rw_bitmask;
thsf1aa6322008-06-09 07:13:38 +00001092}
1093
aurel32d9bea112009-04-15 14:41:44 +00001094void helper_mtc0_srsconf3 (target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001095{
aurel32d9bea112009-04-15 14:41:44 +00001096 env->CP0_SRSConf3 |= arg1 & env->CP0_SRSConf3_rw_bitmask;
thsf1aa6322008-06-09 07:13:38 +00001097}
1098
aurel32d9bea112009-04-15 14:41:44 +00001099void helper_mtc0_srsconf4 (target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001100{
aurel32d9bea112009-04-15 14:41:44 +00001101 env->CP0_SRSConf4 |= arg1 & env->CP0_SRSConf4_rw_bitmask;
thsf1aa6322008-06-09 07:13:38 +00001102}
1103
aurel32d9bea112009-04-15 14:41:44 +00001104void helper_mtc0_hwrena (target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001105{
aurel32d9bea112009-04-15 14:41:44 +00001106 env->CP0_HWREna = arg1 & 0x0000000F;
thsf1aa6322008-06-09 07:13:38 +00001107}
1108
aurel32d9bea112009-04-15 14:41:44 +00001109void helper_mtc0_count (target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001110{
aurel32d9bea112009-04-15 14:41:44 +00001111 cpu_mips_store_count(env, arg1);
thsf1aa6322008-06-09 07:13:38 +00001112}
1113
aurel32d9bea112009-04-15 14:41:44 +00001114void helper_mtc0_entryhi (target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001115{
1116 target_ulong old, val;
1117
1118 /* 1k pages not implemented */
aurel32d9bea112009-04-15 14:41:44 +00001119 val = arg1 & ((TARGET_PAGE_MASK << 1) | 0xFF);
thsf1aa6322008-06-09 07:13:38 +00001120#if defined(TARGET_MIPS64)
1121 val &= env->SEGMask;
1122#endif
1123 old = env->CP0_EntryHi;
1124 env->CP0_EntryHi = val;
1125 if (env->CP0_Config3 & (1 << CP0C3_MT)) {
thsb5dc7732008-06-27 10:02:35 +00001126 uint32_t tcst = env->active_tc.CP0_TCStatus & ~0xff;
1127 env->active_tc.CP0_TCStatus = tcst | (val & 0xff);
thsf1aa6322008-06-09 07:13:38 +00001128 }
1129 /* If the ASID changes, flush qemu's TLB. */
1130 if ((old & 0xFF) != (val & 0xFF))
1131 cpu_mips_tlb_flush(env, 1);
1132}
1133
aurel32d9bea112009-04-15 14:41:44 +00001134void helper_mttc0_entryhi(target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001135{
1136 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
thsb5dc7732008-06-27 10:02:35 +00001137 int32_t tcstatus;
thsf1aa6322008-06-09 07:13:38 +00001138
aurel32d9bea112009-04-15 14:41:44 +00001139 env->CP0_EntryHi = (env->CP0_EntryHi & 0xff) | (arg1 & ~0xff);
thsb5dc7732008-06-27 10:02:35 +00001140 if (other_tc == env->current_tc) {
aurel32d9bea112009-04-15 14:41:44 +00001141 tcstatus = (env->active_tc.CP0_TCStatus & ~0xff) | (arg1 & 0xff);
thsb5dc7732008-06-27 10:02:35 +00001142 env->active_tc.CP0_TCStatus = tcstatus;
1143 } else {
aurel32d9bea112009-04-15 14:41:44 +00001144 tcstatus = (env->tcs[other_tc].CP0_TCStatus & ~0xff) | (arg1 & 0xff);
thsb5dc7732008-06-27 10:02:35 +00001145 env->tcs[other_tc].CP0_TCStatus = tcstatus;
1146 }
thsf1aa6322008-06-09 07:13:38 +00001147}
1148
aurel32d9bea112009-04-15 14:41:44 +00001149void helper_mtc0_compare (target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001150{
aurel32d9bea112009-04-15 14:41:44 +00001151 cpu_mips_store_compare(env, arg1);
thsf1aa6322008-06-09 07:13:38 +00001152}
1153
aurel32d9bea112009-04-15 14:41:44 +00001154void helper_mtc0_status (target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001155{
1156 uint32_t val, old;
1157 uint32_t mask = env->CP0_Status_rw_bitmask;
1158
aurel32d9bea112009-04-15 14:41:44 +00001159 val = arg1 & mask;
thsf1aa6322008-06-09 07:13:38 +00001160 old = env->CP0_Status;
1161 env->CP0_Status = (env->CP0_Status & ~mask) | val;
1162 compute_hflags(env);
aurel32c01fccd2009-03-08 00:06:01 +00001163 if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
1164 qemu_log("Status %08x (%08x) => %08x (%08x) Cause %08x",
1165 old, old & env->CP0_Cause & CP0Ca_IP_mask,
1166 val, val & env->CP0_Cause & CP0Ca_IP_mask,
1167 env->CP0_Cause);
1168 switch (env->hflags & MIPS_HFLAG_KSU) {
1169 case MIPS_HFLAG_UM: qemu_log(", UM\n"); break;
1170 case MIPS_HFLAG_SM: qemu_log(", SM\n"); break;
1171 case MIPS_HFLAG_KM: qemu_log("\n"); break;
1172 default: cpu_abort(env, "Invalid MMU mode!\n"); break;
Aurelien Jarno31e31042009-11-14 13:10:00 +01001173 }
aurel32c01fccd2009-03-08 00:06:01 +00001174 }
thsf1aa6322008-06-09 07:13:38 +00001175 cpu_mips_update_irq(env);
1176}
1177
aurel32d9bea112009-04-15 14:41:44 +00001178void helper_mttc0_status(target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001179{
1180 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
thsb5dc7732008-06-27 10:02:35 +00001181 int32_t tcstatus = env->tcs[other_tc].CP0_TCStatus;
thsf1aa6322008-06-09 07:13:38 +00001182
aurel32d9bea112009-04-15 14:41:44 +00001183 env->CP0_Status = arg1 & ~0xf1000018;
1184 tcstatus = (tcstatus & ~(0xf << CP0TCSt_TCU0)) | (arg1 & (0xf << CP0St_CU0));
1185 tcstatus = (tcstatus & ~(1 << CP0TCSt_TMX)) | ((arg1 & (1 << CP0St_MX)) << (CP0TCSt_TMX - CP0St_MX));
1186 tcstatus = (tcstatus & ~(0x3 << CP0TCSt_TKSU)) | ((arg1 & (0x3 << CP0St_KSU)) << (CP0TCSt_TKSU - CP0St_KSU));
thsb5dc7732008-06-27 10:02:35 +00001187 if (other_tc == env->current_tc)
1188 env->active_tc.CP0_TCStatus = tcstatus;
1189 else
1190 env->tcs[other_tc].CP0_TCStatus = tcstatus;
thsf1aa6322008-06-09 07:13:38 +00001191}
1192
aurel32d9bea112009-04-15 14:41:44 +00001193void helper_mtc0_intctl (target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001194{
1195 /* vectored interrupts not implemented, no performance counters. */
aurel32d9bea112009-04-15 14:41:44 +00001196 env->CP0_IntCtl = (env->CP0_IntCtl & ~0x000002e0) | (arg1 & 0x000002e0);
thsf1aa6322008-06-09 07:13:38 +00001197}
1198
aurel32d9bea112009-04-15 14:41:44 +00001199void helper_mtc0_srsctl (target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001200{
1201 uint32_t mask = (0xf << CP0SRSCtl_ESS) | (0xf << CP0SRSCtl_PSS);
aurel32d9bea112009-04-15 14:41:44 +00001202 env->CP0_SRSCtl = (env->CP0_SRSCtl & ~mask) | (arg1 & mask);
thsf1aa6322008-06-09 07:13:38 +00001203}
1204
aurel32d9bea112009-04-15 14:41:44 +00001205void helper_mtc0_cause (target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001206{
1207 uint32_t mask = 0x00C00300;
1208 uint32_t old = env->CP0_Cause;
1209
1210 if (env->insn_flags & ISA_MIPS32R2)
1211 mask |= 1 << CP0Ca_DC;
1212
aurel32d9bea112009-04-15 14:41:44 +00001213 env->CP0_Cause = (env->CP0_Cause & ~mask) | (arg1 & mask);
thsf1aa6322008-06-09 07:13:38 +00001214
1215 if ((old ^ env->CP0_Cause) & (1 << CP0Ca_DC)) {
1216 if (env->CP0_Cause & (1 << CP0Ca_DC))
1217 cpu_mips_stop_count(env);
1218 else
1219 cpu_mips_start_count(env);
1220 }
1221
1222 /* Handle the software interrupt as an hardware one, as they
1223 are very similar */
aurel32d9bea112009-04-15 14:41:44 +00001224 if (arg1 & CP0Ca_IP_mask) {
thsf1aa6322008-06-09 07:13:38 +00001225 cpu_mips_update_irq(env);
1226 }
1227}
1228
aurel32d9bea112009-04-15 14:41:44 +00001229void helper_mtc0_ebase (target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001230{
1231 /* vectored interrupts not implemented */
1232 /* Multi-CPU not implemented */
aurel32d9bea112009-04-15 14:41:44 +00001233 env->CP0_EBase = 0x80000000 | (arg1 & 0x3FFFF000);
thsf1aa6322008-06-09 07:13:38 +00001234}
1235
aurel32d9bea112009-04-15 14:41:44 +00001236void helper_mtc0_config0 (target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001237{
aurel32d9bea112009-04-15 14:41:44 +00001238 env->CP0_Config0 = (env->CP0_Config0 & 0x81FFFFF8) | (arg1 & 0x00000007);
thsf1aa6322008-06-09 07:13:38 +00001239}
1240
aurel32d9bea112009-04-15 14:41:44 +00001241void helper_mtc0_config2 (target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001242{
1243 /* tertiary/secondary caches not implemented */
1244 env->CP0_Config2 = (env->CP0_Config2 & 0x8FFF0FFF);
1245}
1246
Aurelien Jarno2a6e32d2009-11-22 13:22:54 +01001247void helper_mtc0_lladdr (target_ulong arg1)
1248{
1249 target_long mask = env->CP0_LLAddr_rw_bitmask;
1250 arg1 = arg1 << env->CP0_LLAddr_shift;
1251 env->lladdr = (env->lladdr & ~mask) | (arg1 & mask);
1252}
1253
aurel32d9bea112009-04-15 14:41:44 +00001254void helper_mtc0_watchlo (target_ulong arg1, uint32_t sel)
thsf1aa6322008-06-09 07:13:38 +00001255{
1256 /* Watch exceptions for instructions, data loads, data stores
1257 not implemented. */
aurel32d9bea112009-04-15 14:41:44 +00001258 env->CP0_WatchLo[sel] = (arg1 & ~0x7);
thsf1aa6322008-06-09 07:13:38 +00001259}
1260
aurel32d9bea112009-04-15 14:41:44 +00001261void helper_mtc0_watchhi (target_ulong arg1, uint32_t sel)
thsf1aa6322008-06-09 07:13:38 +00001262{
aurel32d9bea112009-04-15 14:41:44 +00001263 env->CP0_WatchHi[sel] = (arg1 & 0x40FF0FF8);
1264 env->CP0_WatchHi[sel] &= ~(env->CP0_WatchHi[sel] & arg1 & 0x7);
thsf1aa6322008-06-09 07:13:38 +00001265}
1266
aurel32d9bea112009-04-15 14:41:44 +00001267void helper_mtc0_xcontext (target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001268{
1269 target_ulong mask = (1ULL << (env->SEGBITS - 7)) - 1;
aurel32d9bea112009-04-15 14:41:44 +00001270 env->CP0_XContext = (env->CP0_XContext & mask) | (arg1 & ~mask);
thsf1aa6322008-06-09 07:13:38 +00001271}
1272
aurel32d9bea112009-04-15 14:41:44 +00001273void helper_mtc0_framemask (target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001274{
aurel32d9bea112009-04-15 14:41:44 +00001275 env->CP0_Framemask = arg1; /* XXX */
thsf1aa6322008-06-09 07:13:38 +00001276}
1277
aurel32d9bea112009-04-15 14:41:44 +00001278void helper_mtc0_debug (target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001279{
aurel32d9bea112009-04-15 14:41:44 +00001280 env->CP0_Debug = (env->CP0_Debug & 0x8C03FC1F) | (arg1 & 0x13300120);
1281 if (arg1 & (1 << CP0DB_DM))
thsf1aa6322008-06-09 07:13:38 +00001282 env->hflags |= MIPS_HFLAG_DM;
1283 else
1284 env->hflags &= ~MIPS_HFLAG_DM;
1285}
1286
aurel32d9bea112009-04-15 14:41:44 +00001287void helper_mttc0_debug(target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001288{
1289 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
aurel32d9bea112009-04-15 14:41:44 +00001290 uint32_t val = arg1 & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt));
thsf1aa6322008-06-09 07:13:38 +00001291
1292 /* XXX: Might be wrong, check with EJTAG spec. */
thsb5dc7732008-06-27 10:02:35 +00001293 if (other_tc == env->current_tc)
1294 env->active_tc.CP0_Debug_tcstatus = val;
1295 else
1296 env->tcs[other_tc].CP0_Debug_tcstatus = val;
thsf1aa6322008-06-09 07:13:38 +00001297 env->CP0_Debug = (env->CP0_Debug & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
aurel32d9bea112009-04-15 14:41:44 +00001298 (arg1 & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
thsf1aa6322008-06-09 07:13:38 +00001299}
1300
aurel32d9bea112009-04-15 14:41:44 +00001301void helper_mtc0_performance0 (target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001302{
aurel32d9bea112009-04-15 14:41:44 +00001303 env->CP0_Performance0 = arg1 & 0x000007ff;
thsf1aa6322008-06-09 07:13:38 +00001304}
1305
aurel32d9bea112009-04-15 14:41:44 +00001306void helper_mtc0_taglo (target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001307{
aurel32d9bea112009-04-15 14:41:44 +00001308 env->CP0_TagLo = arg1 & 0xFFFFFCF6;
thsf1aa6322008-06-09 07:13:38 +00001309}
1310
aurel32d9bea112009-04-15 14:41:44 +00001311void helper_mtc0_datalo (target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001312{
aurel32d9bea112009-04-15 14:41:44 +00001313 env->CP0_DataLo = arg1; /* XXX */
thsf1aa6322008-06-09 07:13:38 +00001314}
1315
aurel32d9bea112009-04-15 14:41:44 +00001316void helper_mtc0_taghi (target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001317{
aurel32d9bea112009-04-15 14:41:44 +00001318 env->CP0_TagHi = arg1; /* XXX */
thsf1aa6322008-06-09 07:13:38 +00001319}
1320
aurel32d9bea112009-04-15 14:41:44 +00001321void helper_mtc0_datahi (target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001322{
aurel32d9bea112009-04-15 14:41:44 +00001323 env->CP0_DataHi = arg1; /* XXX */
thsf1aa6322008-06-09 07:13:38 +00001324}
1325
thsf1aa6322008-06-09 07:13:38 +00001326/* MIPS MT functions */
aurel32c01fccd2009-03-08 00:06:01 +00001327target_ulong helper_mftgpr(uint32_t sel)
thsf1aa6322008-06-09 07:13:38 +00001328{
1329 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1330
thsb5dc7732008-06-27 10:02:35 +00001331 if (other_tc == env->current_tc)
1332 return env->active_tc.gpr[sel];
1333 else
1334 return env->tcs[other_tc].gpr[sel];
thsf1aa6322008-06-09 07:13:38 +00001335}
1336
aurel32c01fccd2009-03-08 00:06:01 +00001337target_ulong helper_mftlo(uint32_t sel)
thsf1aa6322008-06-09 07:13:38 +00001338{
1339 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1340
thsb5dc7732008-06-27 10:02:35 +00001341 if (other_tc == env->current_tc)
1342 return env->active_tc.LO[sel];
1343 else
1344 return env->tcs[other_tc].LO[sel];
thsf1aa6322008-06-09 07:13:38 +00001345}
1346
aurel32c01fccd2009-03-08 00:06:01 +00001347target_ulong helper_mfthi(uint32_t sel)
thsf1aa6322008-06-09 07:13:38 +00001348{
1349 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1350
thsb5dc7732008-06-27 10:02:35 +00001351 if (other_tc == env->current_tc)
1352 return env->active_tc.HI[sel];
1353 else
1354 return env->tcs[other_tc].HI[sel];
thsf1aa6322008-06-09 07:13:38 +00001355}
1356
aurel32c01fccd2009-03-08 00:06:01 +00001357target_ulong helper_mftacx(uint32_t sel)
thsf1aa6322008-06-09 07:13:38 +00001358{
1359 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1360
thsb5dc7732008-06-27 10:02:35 +00001361 if (other_tc == env->current_tc)
1362 return env->active_tc.ACX[sel];
1363 else
1364 return env->tcs[other_tc].ACX[sel];
thsf1aa6322008-06-09 07:13:38 +00001365}
1366
aurel32c01fccd2009-03-08 00:06:01 +00001367target_ulong helper_mftdsp(void)
thsf1aa6322008-06-09 07:13:38 +00001368{
1369 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1370
thsb5dc7732008-06-27 10:02:35 +00001371 if (other_tc == env->current_tc)
1372 return env->active_tc.DSPControl;
1373 else
1374 return env->tcs[other_tc].DSPControl;
thsf1aa6322008-06-09 07:13:38 +00001375}
1376
aurel32d9bea112009-04-15 14:41:44 +00001377void helper_mttgpr(target_ulong arg1, uint32_t sel)
thsf1aa6322008-06-09 07:13:38 +00001378{
1379 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1380
thsb5dc7732008-06-27 10:02:35 +00001381 if (other_tc == env->current_tc)
aurel32d9bea112009-04-15 14:41:44 +00001382 env->active_tc.gpr[sel] = arg1;
thsb5dc7732008-06-27 10:02:35 +00001383 else
aurel32d9bea112009-04-15 14:41:44 +00001384 env->tcs[other_tc].gpr[sel] = arg1;
thsf1aa6322008-06-09 07:13:38 +00001385}
1386
aurel32d9bea112009-04-15 14:41:44 +00001387void helper_mttlo(target_ulong arg1, uint32_t sel)
thsf1aa6322008-06-09 07:13:38 +00001388{
1389 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1390
thsb5dc7732008-06-27 10:02:35 +00001391 if (other_tc == env->current_tc)
aurel32d9bea112009-04-15 14:41:44 +00001392 env->active_tc.LO[sel] = arg1;
thsb5dc7732008-06-27 10:02:35 +00001393 else
aurel32d9bea112009-04-15 14:41:44 +00001394 env->tcs[other_tc].LO[sel] = arg1;
thsf1aa6322008-06-09 07:13:38 +00001395}
1396
aurel32d9bea112009-04-15 14:41:44 +00001397void helper_mtthi(target_ulong arg1, uint32_t sel)
thsf1aa6322008-06-09 07:13:38 +00001398{
1399 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1400
thsb5dc7732008-06-27 10:02:35 +00001401 if (other_tc == env->current_tc)
aurel32d9bea112009-04-15 14:41:44 +00001402 env->active_tc.HI[sel] = arg1;
thsb5dc7732008-06-27 10:02:35 +00001403 else
aurel32d9bea112009-04-15 14:41:44 +00001404 env->tcs[other_tc].HI[sel] = arg1;
thsf1aa6322008-06-09 07:13:38 +00001405}
1406
aurel32d9bea112009-04-15 14:41:44 +00001407void helper_mttacx(target_ulong arg1, uint32_t sel)
thsf1aa6322008-06-09 07:13:38 +00001408{
1409 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1410
thsb5dc7732008-06-27 10:02:35 +00001411 if (other_tc == env->current_tc)
aurel32d9bea112009-04-15 14:41:44 +00001412 env->active_tc.ACX[sel] = arg1;
thsb5dc7732008-06-27 10:02:35 +00001413 else
aurel32d9bea112009-04-15 14:41:44 +00001414 env->tcs[other_tc].ACX[sel] = arg1;
thsf1aa6322008-06-09 07:13:38 +00001415}
1416
aurel32d9bea112009-04-15 14:41:44 +00001417void helper_mttdsp(target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001418{
1419 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1420
thsb5dc7732008-06-27 10:02:35 +00001421 if (other_tc == env->current_tc)
aurel32d9bea112009-04-15 14:41:44 +00001422 env->active_tc.DSPControl = arg1;
thsb5dc7732008-06-27 10:02:35 +00001423 else
aurel32d9bea112009-04-15 14:41:44 +00001424 env->tcs[other_tc].DSPControl = arg1;
thsf1aa6322008-06-09 07:13:38 +00001425}
1426
1427/* MIPS MT functions */
aurel32d9bea112009-04-15 14:41:44 +00001428target_ulong helper_dmt(target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001429{
1430 // TODO
aurel32d9bea112009-04-15 14:41:44 +00001431 arg1 = 0;
1432 // rt = arg1
thsbe24bb42008-06-23 12:57:09 +00001433
aurel32d9bea112009-04-15 14:41:44 +00001434 return arg1;
thsf1aa6322008-06-09 07:13:38 +00001435}
1436
aurel32d9bea112009-04-15 14:41:44 +00001437target_ulong helper_emt(target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001438{
1439 // TODO
aurel32d9bea112009-04-15 14:41:44 +00001440 arg1 = 0;
1441 // rt = arg1
thsbe24bb42008-06-23 12:57:09 +00001442
aurel32d9bea112009-04-15 14:41:44 +00001443 return arg1;
thsf1aa6322008-06-09 07:13:38 +00001444}
1445
aurel32d9bea112009-04-15 14:41:44 +00001446target_ulong helper_dvpe(target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001447{
1448 // TODO
aurel32d9bea112009-04-15 14:41:44 +00001449 arg1 = 0;
1450 // rt = arg1
thsbe24bb42008-06-23 12:57:09 +00001451
aurel32d9bea112009-04-15 14:41:44 +00001452 return arg1;
thsf1aa6322008-06-09 07:13:38 +00001453}
1454
aurel32d9bea112009-04-15 14:41:44 +00001455target_ulong helper_evpe(target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001456{
1457 // TODO
aurel32d9bea112009-04-15 14:41:44 +00001458 arg1 = 0;
1459 // rt = arg1
thsbe24bb42008-06-23 12:57:09 +00001460
aurel32d9bea112009-04-15 14:41:44 +00001461 return arg1;
thsf1aa6322008-06-09 07:13:38 +00001462}
thsf9480ff2008-12-20 19:42:14 +00001463#endif /* !CONFIG_USER_ONLY */
thsf1aa6322008-06-09 07:13:38 +00001464
aurel32d9bea112009-04-15 14:41:44 +00001465void helper_fork(target_ulong arg1, target_ulong arg2)
thsf1aa6322008-06-09 07:13:38 +00001466{
aurel32d9bea112009-04-15 14:41:44 +00001467 // arg1 = rt, arg2 = rs
1468 arg1 = 0;
thsf1aa6322008-06-09 07:13:38 +00001469 // TODO: store to TC register
1470}
1471
aurel32d9bea112009-04-15 14:41:44 +00001472target_ulong helper_yield(target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001473{
aurel32d9bea112009-04-15 14:41:44 +00001474 if (arg1 < 0) {
thsf1aa6322008-06-09 07:13:38 +00001475 /* No scheduling policy implemented. */
aurel32d9bea112009-04-15 14:41:44 +00001476 if (arg1 != -2) {
thsf1aa6322008-06-09 07:13:38 +00001477 if (env->CP0_VPEControl & (1 << CP0VPECo_YSI) &&
thsb5dc7732008-06-27 10:02:35 +00001478 env->active_tc.CP0_TCStatus & (1 << CP0TCSt_DT)) {
thsf1aa6322008-06-09 07:13:38 +00001479 env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
1480 env->CP0_VPEControl |= 4 << CP0VPECo_EXCPT;
aurel32c01fccd2009-03-08 00:06:01 +00001481 helper_raise_exception(EXCP_THREAD);
thsf1aa6322008-06-09 07:13:38 +00001482 }
1483 }
aurel32d9bea112009-04-15 14:41:44 +00001484 } else if (arg1 == 0) {
aurel3269585492009-01-14 19:40:36 +00001485 if (0 /* TODO: TC underflow */) {
thsf1aa6322008-06-09 07:13:38 +00001486 env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
aurel32c01fccd2009-03-08 00:06:01 +00001487 helper_raise_exception(EXCP_THREAD);
thsf1aa6322008-06-09 07:13:38 +00001488 } else {
1489 // TODO: Deallocate TC
1490 }
aurel32d9bea112009-04-15 14:41:44 +00001491 } else if (arg1 > 0) {
thsf1aa6322008-06-09 07:13:38 +00001492 /* Yield qualifier inputs not implemented. */
1493 env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
1494 env->CP0_VPEControl |= 2 << CP0VPECo_EXCPT;
aurel32c01fccd2009-03-08 00:06:01 +00001495 helper_raise_exception(EXCP_THREAD);
thsf1aa6322008-06-09 07:13:38 +00001496 }
thsbe24bb42008-06-23 12:57:09 +00001497 return env->CP0_YQMask;
thsf1aa6322008-06-09 07:13:38 +00001498}
1499
thsf1aa6322008-06-09 07:13:38 +00001500#ifndef CONFIG_USER_ONLY
bellard6af0bf92005-07-02 14:58:51 +00001501/* TLB management */
ths814b9a42006-12-06 17:42:40 +00001502void cpu_mips_tlb_flush (CPUState *env, int flush_global)
1503{
1504 /* Flush qemu's TLB and discard all shadowed entries. */
1505 tlb_flush (env, flush_global);
thsead93602007-09-06 00:18:15 +00001506 env->tlb->tlb_in_use = env->tlb->nb_tlb;
ths814b9a42006-12-06 17:42:40 +00001507}
1508
ths29929e32007-05-13 13:49:44 +00001509static void r4k_mips_tlb_flush_extra (CPUState *env, int first)
ths814b9a42006-12-06 17:42:40 +00001510{
1511 /* Discard entries from env->tlb[first] onwards. */
thsead93602007-09-06 00:18:15 +00001512 while (env->tlb->tlb_in_use > first) {
1513 r4k_invalidate_tlb(env, --env->tlb->tlb_in_use, 0);
ths814b9a42006-12-06 17:42:40 +00001514 }
1515}
1516
ths29929e32007-05-13 13:49:44 +00001517static void r4k_fill_tlb (int idx)
bellard6af0bf92005-07-02 14:58:51 +00001518{
Anthony Liguoric227f092009-10-01 16:12:16 -05001519 r4k_tlb_t *tlb;
bellard6af0bf92005-07-02 14:58:51 +00001520
1521 /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */
thsead93602007-09-06 00:18:15 +00001522 tlb = &env->tlb->mmu.r4k.tlb[idx];
thsf2e9ebe2007-05-13 14:07:26 +00001523 tlb->VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1);
thsd26bc212007-11-08 18:05:37 +00001524#if defined(TARGET_MIPS64)
thse034e2c2007-06-23 18:04:12 +00001525 tlb->VPN &= env->SEGMask;
ths100ce982007-05-13 19:22:13 +00001526#endif
pbrook98c1b822006-03-11 16:20:36 +00001527 tlb->ASID = env->CP0_EntryHi & 0xFF;
ths3b1c8be2007-01-22 20:50:42 +00001528 tlb->PageMask = env->CP0_PageMask;
bellard6af0bf92005-07-02 14:58:51 +00001529 tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
pbrook98c1b822006-03-11 16:20:36 +00001530 tlb->V0 = (env->CP0_EntryLo0 & 2) != 0;
1531 tlb->D0 = (env->CP0_EntryLo0 & 4) != 0;
1532 tlb->C0 = (env->CP0_EntryLo0 >> 3) & 0x7;
bellard6af0bf92005-07-02 14:58:51 +00001533 tlb->PFN[0] = (env->CP0_EntryLo0 >> 6) << 12;
pbrook98c1b822006-03-11 16:20:36 +00001534 tlb->V1 = (env->CP0_EntryLo1 & 2) != 0;
1535 tlb->D1 = (env->CP0_EntryLo1 & 4) != 0;
1536 tlb->C1 = (env->CP0_EntryLo1 >> 3) & 0x7;
bellard6af0bf92005-07-02 14:58:51 +00001537 tlb->PFN[1] = (env->CP0_EntryLo1 >> 6) << 12;
1538}
1539
aurel32c01fccd2009-03-08 00:06:01 +00001540void r4k_helper_tlbwi (void)
bellard6af0bf92005-07-02 14:58:51 +00001541{
aurel32bbc0d792008-09-14 17:09:56 +00001542 int idx;
1543
1544 idx = (env->CP0_Index & ~0x80000000) % env->tlb->nb_tlb;
1545
ths814b9a42006-12-06 17:42:40 +00001546 /* Discard cached TLB entries. We could avoid doing this if the
1547 tlbwi is just upgrading access permissions on the current entry;
1548 that might be a further win. */
thsead93602007-09-06 00:18:15 +00001549 r4k_mips_tlb_flush_extra (env, env->tlb->nb_tlb);
ths814b9a42006-12-06 17:42:40 +00001550
aurel32bbc0d792008-09-14 17:09:56 +00001551 r4k_invalidate_tlb(env, idx, 0);
1552 r4k_fill_tlb(idx);
bellard6af0bf92005-07-02 14:58:51 +00001553}
1554
aurel32c01fccd2009-03-08 00:06:01 +00001555void r4k_helper_tlbwr (void)
bellard6af0bf92005-07-02 14:58:51 +00001556{
1557 int r = cpu_mips_get_random(env);
1558
ths29929e32007-05-13 13:49:44 +00001559 r4k_invalidate_tlb(env, r, 1);
1560 r4k_fill_tlb(r);
bellard6af0bf92005-07-02 14:58:51 +00001561}
1562
aurel32c01fccd2009-03-08 00:06:01 +00001563void r4k_helper_tlbp (void)
bellard6af0bf92005-07-02 14:58:51 +00001564{
Anthony Liguoric227f092009-10-01 16:12:16 -05001565 r4k_tlb_t *tlb;
thsf2e9ebe2007-05-13 14:07:26 +00001566 target_ulong mask;
bellard6af0bf92005-07-02 14:58:51 +00001567 target_ulong tag;
thsf2e9ebe2007-05-13 14:07:26 +00001568 target_ulong VPN;
bellard6af0bf92005-07-02 14:58:51 +00001569 uint8_t ASID;
1570 int i;
1571
bellard3d9fb9fe2006-05-22 22:13:29 +00001572 ASID = env->CP0_EntryHi & 0xFF;
thsead93602007-09-06 00:18:15 +00001573 for (i = 0; i < env->tlb->nb_tlb; i++) {
1574 tlb = &env->tlb->mmu.r4k.tlb[i];
thsf2e9ebe2007-05-13 14:07:26 +00001575 /* 1k pages are not supported. */
1576 mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
1577 tag = env->CP0_EntryHi & ~mask;
1578 VPN = tlb->VPN & ~mask;
bellard6af0bf92005-07-02 14:58:51 +00001579 /* Check ASID, virtual page number & size */
thsf2e9ebe2007-05-13 14:07:26 +00001580 if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
bellard6af0bf92005-07-02 14:58:51 +00001581 /* TLB match */
ths9c2149c2007-01-23 22:45:22 +00001582 env->CP0_Index = i;
bellard6af0bf92005-07-02 14:58:51 +00001583 break;
1584 }
1585 }
thsead93602007-09-06 00:18:15 +00001586 if (i == env->tlb->nb_tlb) {
ths814b9a42006-12-06 17:42:40 +00001587 /* No match. Discard any shadow entries, if any of them match. */
thsead93602007-09-06 00:18:15 +00001588 for (i = env->tlb->nb_tlb; i < env->tlb->tlb_in_use; i++) {
aurel3269585492009-01-14 19:40:36 +00001589 tlb = &env->tlb->mmu.r4k.tlb[i];
1590 /* 1k pages are not supported. */
1591 mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
1592 tag = env->CP0_EntryHi & ~mask;
1593 VPN = tlb->VPN & ~mask;
1594 /* Check ASID, virtual page number & size */
1595 if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
ths29929e32007-05-13 13:49:44 +00001596 r4k_mips_tlb_flush_extra (env, i);
aurel3269585492009-01-14 19:40:36 +00001597 break;
1598 }
1599 }
ths814b9a42006-12-06 17:42:40 +00001600
ths9c2149c2007-01-23 22:45:22 +00001601 env->CP0_Index |= 0x80000000;
bellard6af0bf92005-07-02 14:58:51 +00001602 }
1603}
1604
aurel32c01fccd2009-03-08 00:06:01 +00001605void r4k_helper_tlbr (void)
bellard6af0bf92005-07-02 14:58:51 +00001606{
Anthony Liguoric227f092009-10-01 16:12:16 -05001607 r4k_tlb_t *tlb;
pbrook09c56b82006-03-11 16:39:23 +00001608 uint8_t ASID;
aurel32bbc0d792008-09-14 17:09:56 +00001609 int idx;
bellard6af0bf92005-07-02 14:58:51 +00001610
pbrook09c56b82006-03-11 16:39:23 +00001611 ASID = env->CP0_EntryHi & 0xFF;
aurel32bbc0d792008-09-14 17:09:56 +00001612 idx = (env->CP0_Index & ~0x80000000) % env->tlb->nb_tlb;
1613 tlb = &env->tlb->mmu.r4k.tlb[idx];
bellard4ad40f32005-12-05 19:59:36 +00001614
1615 /* If this will change the current ASID, flush qemu's TLB. */
ths814b9a42006-12-06 17:42:40 +00001616 if (ASID != tlb->ASID)
1617 cpu_mips_tlb_flush (env, 1);
1618
thsead93602007-09-06 00:18:15 +00001619 r4k_mips_tlb_flush_extra(env, env->tlb->nb_tlb);
bellard4ad40f32005-12-05 19:59:36 +00001620
bellard6af0bf92005-07-02 14:58:51 +00001621 env->CP0_EntryHi = tlb->VPN | tlb->ASID;
ths3b1c8be2007-01-22 20:50:42 +00001622 env->CP0_PageMask = tlb->PageMask;
ths7495fd02007-01-01 20:32:08 +00001623 env->CP0_EntryLo0 = tlb->G | (tlb->V0 << 1) | (tlb->D0 << 2) |
1624 (tlb->C0 << 3) | (tlb->PFN[0] >> 6);
1625 env->CP0_EntryLo1 = tlb->G | (tlb->V1 << 1) | (tlb->D1 << 2) |
1626 (tlb->C1 << 3) | (tlb->PFN[1] >> 6);
bellard6af0bf92005-07-02 14:58:51 +00001627}
bellard6af0bf92005-07-02 14:58:51 +00001628
aurel32c01fccd2009-03-08 00:06:01 +00001629void helper_tlbwi(void)
pbrooka7812ae2008-11-17 14:43:54 +00001630{
aurel32c01fccd2009-03-08 00:06:01 +00001631 env->tlb->helper_tlbwi();
pbrooka7812ae2008-11-17 14:43:54 +00001632}
1633
aurel32c01fccd2009-03-08 00:06:01 +00001634void helper_tlbwr(void)
pbrooka7812ae2008-11-17 14:43:54 +00001635{
aurel32c01fccd2009-03-08 00:06:01 +00001636 env->tlb->helper_tlbwr();
pbrooka7812ae2008-11-17 14:43:54 +00001637}
1638
aurel32c01fccd2009-03-08 00:06:01 +00001639void helper_tlbp(void)
pbrooka7812ae2008-11-17 14:43:54 +00001640{
aurel32c01fccd2009-03-08 00:06:01 +00001641 env->tlb->helper_tlbp();
pbrooka7812ae2008-11-17 14:43:54 +00001642}
1643
aurel32c01fccd2009-03-08 00:06:01 +00001644void helper_tlbr(void)
pbrooka7812ae2008-11-17 14:43:54 +00001645{
aurel32c01fccd2009-03-08 00:06:01 +00001646 env->tlb->helper_tlbr();
pbrooka7812ae2008-11-17 14:43:54 +00001647}
1648
ths2b0233a2008-06-12 12:42:35 +00001649/* Specials */
aurel32c01fccd2009-03-08 00:06:01 +00001650target_ulong helper_di (void)
ths2b0233a2008-06-12 12:42:35 +00001651{
ths27961882008-06-27 10:03:42 +00001652 target_ulong t0 = env->CP0_Status;
1653
thsbe24bb42008-06-23 12:57:09 +00001654 env->CP0_Status = t0 & ~(1 << CP0St_IE);
ths2b0233a2008-06-12 12:42:35 +00001655 cpu_mips_update_irq(env);
thsbe24bb42008-06-23 12:57:09 +00001656
1657 return t0;
ths2b0233a2008-06-12 12:42:35 +00001658}
1659
aurel32c01fccd2009-03-08 00:06:01 +00001660target_ulong helper_ei (void)
ths2b0233a2008-06-12 12:42:35 +00001661{
ths27961882008-06-27 10:03:42 +00001662 target_ulong t0 = env->CP0_Status;
1663
thsbe24bb42008-06-23 12:57:09 +00001664 env->CP0_Status = t0 | (1 << CP0St_IE);
ths2b0233a2008-06-12 12:42:35 +00001665 cpu_mips_update_irq(env);
thsbe24bb42008-06-23 12:57:09 +00001666
1667 return t0;
ths2b0233a2008-06-12 12:42:35 +00001668}
1669
aurel32cd5158e2008-12-07 23:26:24 +00001670static void debug_pre_eret (void)
bellard6af0bf92005-07-02 14:58:51 +00001671{
aliguori8fec2b82009-01-15 22:36:53 +00001672 if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
aliguori93fcfe32009-01-15 22:34:14 +00001673 qemu_log("ERET: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
1674 env->active_tc.PC, env->CP0_EPC);
1675 if (env->CP0_Status & (1 << CP0St_ERL))
1676 qemu_log(" ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
1677 if (env->hflags & MIPS_HFLAG_DM)
1678 qemu_log(" DEPC " TARGET_FMT_lx, env->CP0_DEPC);
1679 qemu_log("\n");
1680 }
thsf41c52f2007-04-06 18:46:01 +00001681}
1682
aurel32cd5158e2008-12-07 23:26:24 +00001683static void debug_post_eret (void)
thsf41c52f2007-04-06 18:46:01 +00001684{
aliguori8fec2b82009-01-15 22:36:53 +00001685 if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
aliguori93fcfe32009-01-15 22:34:14 +00001686 qemu_log(" => PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
1687 env->active_tc.PC, env->CP0_EPC);
1688 if (env->CP0_Status & (1 << CP0St_ERL))
1689 qemu_log(" ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
1690 if (env->hflags & MIPS_HFLAG_DM)
1691 qemu_log(" DEPC " TARGET_FMT_lx, env->CP0_DEPC);
1692 switch (env->hflags & MIPS_HFLAG_KSU) {
1693 case MIPS_HFLAG_UM: qemu_log(", UM\n"); break;
1694 case MIPS_HFLAG_SM: qemu_log(", SM\n"); break;
1695 case MIPS_HFLAG_KM: qemu_log("\n"); break;
1696 default: cpu_abort(env, "Invalid MMU mode!\n"); break;
1697 }
ths623a9302007-10-28 19:45:05 +00001698 }
bellard6af0bf92005-07-02 14:58:51 +00001699}
1700
Nathan Froyd32188a02009-12-08 08:06:23 -08001701static void set_pc (target_ulong error_pc)
1702{
1703 env->active_tc.PC = error_pc & ~(target_ulong)1;
1704 if (error_pc & 1) {
1705 env->hflags |= MIPS_HFLAG_M16;
1706 } else {
1707 env->hflags &= ~(MIPS_HFLAG_M16);
1708 }
1709}
1710
aurel32c01fccd2009-03-08 00:06:01 +00001711void helper_eret (void)
ths2b0233a2008-06-12 12:42:35 +00001712{
aliguori93fcfe32009-01-15 22:34:14 +00001713 debug_pre_eret();
ths2b0233a2008-06-12 12:42:35 +00001714 if (env->CP0_Status & (1 << CP0St_ERL)) {
Nathan Froyd32188a02009-12-08 08:06:23 -08001715 set_pc(env->CP0_ErrorEPC);
ths2b0233a2008-06-12 12:42:35 +00001716 env->CP0_Status &= ~(1 << CP0St_ERL);
1717 } else {
Nathan Froyd32188a02009-12-08 08:06:23 -08001718 set_pc(env->CP0_EPC);
ths2b0233a2008-06-12 12:42:35 +00001719 env->CP0_Status &= ~(1 << CP0St_EXL);
1720 }
1721 compute_hflags(env);
aliguori93fcfe32009-01-15 22:34:14 +00001722 debug_post_eret();
Aurelien Jarno5499b6f2009-11-22 13:08:14 +01001723 env->lladdr = 1;
ths2b0233a2008-06-12 12:42:35 +00001724}
1725
aurel32c01fccd2009-03-08 00:06:01 +00001726void helper_deret (void)
ths2b0233a2008-06-12 12:42:35 +00001727{
aliguori93fcfe32009-01-15 22:34:14 +00001728 debug_pre_eret();
Nathan Froyd32188a02009-12-08 08:06:23 -08001729 set_pc(env->CP0_DEPC);
1730
ths2b0233a2008-06-12 12:42:35 +00001731 env->hflags &= MIPS_HFLAG_DM;
1732 compute_hflags(env);
aliguori93fcfe32009-01-15 22:34:14 +00001733 debug_post_eret();
Aurelien Jarno5499b6f2009-11-22 13:08:14 +01001734 env->lladdr = 1;
ths2b0233a2008-06-12 12:42:35 +00001735}
ths0eaef5a2008-07-23 16:14:22 +00001736#endif /* !CONFIG_USER_ONLY */
ths2b0233a2008-06-12 12:42:35 +00001737
aurel32c01fccd2009-03-08 00:06:01 +00001738target_ulong helper_rdhwr_cpunum(void)
ths2b0233a2008-06-12 12:42:35 +00001739{
1740 if ((env->hflags & MIPS_HFLAG_CP0) ||
1741 (env->CP0_HWREna & (1 << 0)))
ths27961882008-06-27 10:03:42 +00001742 return env->CP0_EBase & 0x3ff;
ths2b0233a2008-06-12 12:42:35 +00001743 else
aurel32c01fccd2009-03-08 00:06:01 +00001744 helper_raise_exception(EXCP_RI);
thsbe24bb42008-06-23 12:57:09 +00001745
ths27961882008-06-27 10:03:42 +00001746 return 0;
ths2b0233a2008-06-12 12:42:35 +00001747}
1748
aurel32c01fccd2009-03-08 00:06:01 +00001749target_ulong helper_rdhwr_synci_step(void)
ths2b0233a2008-06-12 12:42:35 +00001750{
1751 if ((env->hflags & MIPS_HFLAG_CP0) ||
1752 (env->CP0_HWREna & (1 << 1)))
ths27961882008-06-27 10:03:42 +00001753 return env->SYNCI_Step;
ths2b0233a2008-06-12 12:42:35 +00001754 else
aurel32c01fccd2009-03-08 00:06:01 +00001755 helper_raise_exception(EXCP_RI);
thsbe24bb42008-06-23 12:57:09 +00001756
ths27961882008-06-27 10:03:42 +00001757 return 0;
ths2b0233a2008-06-12 12:42:35 +00001758}
1759
aurel32c01fccd2009-03-08 00:06:01 +00001760target_ulong helper_rdhwr_cc(void)
ths2b0233a2008-06-12 12:42:35 +00001761{
1762 if ((env->hflags & MIPS_HFLAG_CP0) ||
1763 (env->CP0_HWREna & (1 << 2)))
ths27961882008-06-27 10:03:42 +00001764 return env->CP0_Count;
ths2b0233a2008-06-12 12:42:35 +00001765 else
aurel32c01fccd2009-03-08 00:06:01 +00001766 helper_raise_exception(EXCP_RI);
thsbe24bb42008-06-23 12:57:09 +00001767
ths27961882008-06-27 10:03:42 +00001768 return 0;
ths2b0233a2008-06-12 12:42:35 +00001769}
1770
aurel32c01fccd2009-03-08 00:06:01 +00001771target_ulong helper_rdhwr_ccres(void)
ths2b0233a2008-06-12 12:42:35 +00001772{
1773 if ((env->hflags & MIPS_HFLAG_CP0) ||
1774 (env->CP0_HWREna & (1 << 3)))
ths27961882008-06-27 10:03:42 +00001775 return env->CCRes;
ths2b0233a2008-06-12 12:42:35 +00001776 else
aurel32c01fccd2009-03-08 00:06:01 +00001777 helper_raise_exception(EXCP_RI);
thsbe24bb42008-06-23 12:57:09 +00001778
ths27961882008-06-27 10:03:42 +00001779 return 0;
ths2b0233a2008-06-12 12:42:35 +00001780}
1781
aurel32c01fccd2009-03-08 00:06:01 +00001782void helper_pmon (int function)
bellard6af0bf92005-07-02 14:58:51 +00001783{
1784 function /= 2;
1785 switch (function) {
1786 case 2: /* TODO: char inbyte(int waitflag); */
thsb5dc7732008-06-27 10:02:35 +00001787 if (env->active_tc.gpr[4] == 0)
1788 env->active_tc.gpr[2] = -1;
bellard6af0bf92005-07-02 14:58:51 +00001789 /* Fall through */
1790 case 11: /* TODO: char inbyte (void); */
thsb5dc7732008-06-27 10:02:35 +00001791 env->active_tc.gpr[2] = -1;
bellard6af0bf92005-07-02 14:58:51 +00001792 break;
1793 case 3:
1794 case 12:
thsb5dc7732008-06-27 10:02:35 +00001795 printf("%c", (char)(env->active_tc.gpr[4] & 0xFF));
bellard6af0bf92005-07-02 14:58:51 +00001796 break;
1797 case 17:
1798 break;
1799 case 158:
1800 {
thsb5dc7732008-06-27 10:02:35 +00001801 unsigned char *fmt = (void *)(unsigned long)env->active_tc.gpr[4];
bellard6af0bf92005-07-02 14:58:51 +00001802 printf("%s", fmt);
1803 }
1804 break;
1805 }
1806}
bellarde37e8632005-07-04 22:17:33 +00001807
aurel32c01fccd2009-03-08 00:06:01 +00001808void helper_wait (void)
ths08ba7962008-06-12 03:15:13 +00001809{
1810 env->halted = 1;
aurel32c01fccd2009-03-08 00:06:01 +00001811 helper_raise_exception(EXCP_HLT);
ths08ba7962008-06-12 03:15:13 +00001812}
1813
ths5fafdf22007-09-16 21:08:06 +00001814#if !defined(CONFIG_USER_ONLY)
bellarde37e8632005-07-04 22:17:33 +00001815
bellard4ad40f32005-12-05 19:59:36 +00001816static void do_unaligned_access (target_ulong addr, int is_write, int is_user, void *retaddr);
1817
bellarde37e8632005-07-04 22:17:33 +00001818#define MMUSUFFIX _mmu
bellard4ad40f32005-12-05 19:59:36 +00001819#define ALIGNED_ONLY
bellarde37e8632005-07-04 22:17:33 +00001820
1821#define SHIFT 0
1822#include "softmmu_template.h"
1823
1824#define SHIFT 1
1825#include "softmmu_template.h"
1826
1827#define SHIFT 2
1828#include "softmmu_template.h"
1829
1830#define SHIFT 3
1831#include "softmmu_template.h"
1832
bellard4ad40f32005-12-05 19:59:36 +00001833static void do_unaligned_access (target_ulong addr, int is_write, int is_user, void *retaddr)
1834{
1835 env->CP0_BadVAddr = addr;
1836 do_restore_state (retaddr);
aurel32c01fccd2009-03-08 00:06:01 +00001837 helper_raise_exception ((is_write == 1) ? EXCP_AdES : EXCP_AdEL);
bellard4ad40f32005-12-05 19:59:36 +00001838}
1839
j_mayer6ebbf392007-10-14 07:07:08 +00001840void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
bellarde37e8632005-07-04 22:17:33 +00001841{
1842 TranslationBlock *tb;
1843 CPUState *saved_env;
1844 unsigned long pc;
1845 int ret;
1846
1847 /* XXX: hack to restore env in all cases, even if not called from
1848 generated code */
1849 saved_env = env;
1850 env = cpu_single_env;
j_mayer6ebbf392007-10-14 07:07:08 +00001851 ret = cpu_mips_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
bellarde37e8632005-07-04 22:17:33 +00001852 if (ret) {
1853 if (retaddr) {
1854 /* now we have a real cpu fault */
1855 pc = (unsigned long)retaddr;
1856 tb = tb_find_pc(pc);
1857 if (tb) {
1858 /* the PC is inside the translated code. It means that we have
1859 a virtual CPU fault */
1860 cpu_restore_state(tb, env, pc, NULL);
1861 }
1862 }
aurel32c01fccd2009-03-08 00:06:01 +00001863 helper_raise_exception_err(env->exception_index, env->error_code);
bellarde37e8632005-07-04 22:17:33 +00001864 }
1865 env = saved_env;
1866}
1867
Anthony Liguoric227f092009-10-01 16:12:16 -05001868void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
blueswir1e18231a2008-10-06 18:46:28 +00001869 int unused, int size)
ths647de6c2007-10-20 19:45:44 +00001870{
1871 if (is_exec)
aurel32c01fccd2009-03-08 00:06:01 +00001872 helper_raise_exception(EXCP_IBE);
ths647de6c2007-10-20 19:45:44 +00001873 else
aurel32c01fccd2009-03-08 00:06:01 +00001874 helper_raise_exception(EXCP_DBE);
ths647de6c2007-10-20 19:45:44 +00001875}
thsf1aa6322008-06-09 07:13:38 +00001876#endif /* !CONFIG_USER_ONLY */
thsfd4a04e2007-05-18 11:55:54 +00001877
1878/* Complex FPU operations which may need stack space. */
1879
pbrookf090c9d2007-11-18 14:33:24 +00001880#define FLOAT_ONE32 make_float32(0x3f8 << 20)
1881#define FLOAT_ONE64 make_float64(0x3ffULL << 52)
1882#define FLOAT_TWO32 make_float32(1 << 30)
1883#define FLOAT_TWO64 make_float64(1ULL << 62)
ths54454092007-09-29 19:19:59 +00001884#define FLOAT_QNAN32 0x7fbfffff
1885#define FLOAT_QNAN64 0x7ff7ffffffffffffULL
1886#define FLOAT_SNAN32 0x7fffffff
1887#define FLOAT_SNAN64 0x7fffffffffffffffULL
ths8dfdb872007-06-26 20:26:03 +00001888
thsfd4a04e2007-05-18 11:55:54 +00001889/* convert MIPS rounding mode in FCR31 to IEEE library */
Blue Swirl6f4fc362009-09-21 18:39:26 +00001890static unsigned int ieee_rm[] = {
thsfd4a04e2007-05-18 11:55:54 +00001891 float_round_nearest_even,
1892 float_round_to_zero,
1893 float_round_up,
1894 float_round_down
1895};
1896
1897#define RESTORE_ROUNDING_MODE \
thsf01be152008-09-18 11:57:27 +00001898 set_float_rounding_mode(ieee_rm[env->active_fpu.fcr31 & 3], &env->active_fpu.fp_status)
thsfd4a04e2007-05-18 11:55:54 +00001899
aurel3241e0c702009-03-28 22:22:40 +00001900#define RESTORE_FLUSH_MODE \
1901 set_flush_to_zero((env->active_fpu.fcr31 & (1 << 24)) != 0, &env->active_fpu.fp_status);
1902
aurel32c01fccd2009-03-08 00:06:01 +00001903target_ulong helper_cfc1 (uint32_t reg)
thsfd4a04e2007-05-18 11:55:54 +00001904{
aurel32d9bea112009-04-15 14:41:44 +00001905 target_ulong arg1;
ths6c5c1e22008-06-24 15:12:27 +00001906
thsead93602007-09-06 00:18:15 +00001907 switch (reg) {
1908 case 0:
aurel32d9bea112009-04-15 14:41:44 +00001909 arg1 = (int32_t)env->active_fpu.fcr0;
thsead93602007-09-06 00:18:15 +00001910 break;
1911 case 25:
aurel32d9bea112009-04-15 14:41:44 +00001912 arg1 = ((env->active_fpu.fcr31 >> 24) & 0xfe) | ((env->active_fpu.fcr31 >> 23) & 0x1);
thsead93602007-09-06 00:18:15 +00001913 break;
1914 case 26:
aurel32d9bea112009-04-15 14:41:44 +00001915 arg1 = env->active_fpu.fcr31 & 0x0003f07c;
thsead93602007-09-06 00:18:15 +00001916 break;
1917 case 28:
aurel32d9bea112009-04-15 14:41:44 +00001918 arg1 = (env->active_fpu.fcr31 & 0x00000f83) | ((env->active_fpu.fcr31 >> 22) & 0x4);
thsead93602007-09-06 00:18:15 +00001919 break;
1920 default:
aurel32d9bea112009-04-15 14:41:44 +00001921 arg1 = (int32_t)env->active_fpu.fcr31;
thsead93602007-09-06 00:18:15 +00001922 break;
1923 }
thsbe24bb42008-06-23 12:57:09 +00001924
aurel32d9bea112009-04-15 14:41:44 +00001925 return arg1;
thsead93602007-09-06 00:18:15 +00001926}
1927
aurel32d9bea112009-04-15 14:41:44 +00001928void helper_ctc1 (target_ulong arg1, uint32_t reg)
thsead93602007-09-06 00:18:15 +00001929{
1930 switch(reg) {
thsfd4a04e2007-05-18 11:55:54 +00001931 case 25:
aurel32d9bea112009-04-15 14:41:44 +00001932 if (arg1 & 0xffffff00)
thsfd4a04e2007-05-18 11:55:54 +00001933 return;
aurel32d9bea112009-04-15 14:41:44 +00001934 env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0x017fffff) | ((arg1 & 0xfe) << 24) |
1935 ((arg1 & 0x1) << 23);
thsfd4a04e2007-05-18 11:55:54 +00001936 break;
1937 case 26:
aurel32d9bea112009-04-15 14:41:44 +00001938 if (arg1 & 0x007c0000)
thsfd4a04e2007-05-18 11:55:54 +00001939 return;
aurel32d9bea112009-04-15 14:41:44 +00001940 env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0xfffc0f83) | (arg1 & 0x0003f07c);
thsfd4a04e2007-05-18 11:55:54 +00001941 break;
1942 case 28:
aurel32d9bea112009-04-15 14:41:44 +00001943 if (arg1 & 0x007c0000)
thsfd4a04e2007-05-18 11:55:54 +00001944 return;
aurel32d9bea112009-04-15 14:41:44 +00001945 env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0xfefff07c) | (arg1 & 0x00000f83) |
1946 ((arg1 & 0x4) << 22);
thsfd4a04e2007-05-18 11:55:54 +00001947 break;
1948 case 31:
aurel32d9bea112009-04-15 14:41:44 +00001949 if (arg1 & 0x007c0000)
thsfd4a04e2007-05-18 11:55:54 +00001950 return;
aurel32d9bea112009-04-15 14:41:44 +00001951 env->active_fpu.fcr31 = arg1;
thsfd4a04e2007-05-18 11:55:54 +00001952 break;
1953 default:
1954 return;
1955 }
1956 /* set rounding mode */
1957 RESTORE_ROUNDING_MODE;
aurel3241e0c702009-03-28 22:22:40 +00001958 /* set flush-to-zero mode */
1959 RESTORE_FLUSH_MODE;
thsf01be152008-09-18 11:57:27 +00001960 set_float_exception_flags(0, &env->active_fpu.fp_status);
1961 if ((GET_FP_ENABLE(env->active_fpu.fcr31) | 0x20) & GET_FP_CAUSE(env->active_fpu.fcr31))
aurel32c01fccd2009-03-08 00:06:01 +00001962 helper_raise_exception(EXCP_FPE);
thsfd4a04e2007-05-18 11:55:54 +00001963}
1964
thsc904ef02008-07-23 16:16:31 +00001965static inline char ieee_ex_to_mips(char xcpt)
thsfd4a04e2007-05-18 11:55:54 +00001966{
1967 return (xcpt & float_flag_inexact) >> 5 |
1968 (xcpt & float_flag_underflow) >> 3 |
1969 (xcpt & float_flag_overflow) >> 1 |
1970 (xcpt & float_flag_divbyzero) << 1 |
1971 (xcpt & float_flag_invalid) << 4;
1972}
1973
thsc904ef02008-07-23 16:16:31 +00001974static inline char mips_ex_to_ieee(char xcpt)
thsfd4a04e2007-05-18 11:55:54 +00001975{
1976 return (xcpt & FP_INEXACT) << 5 |
1977 (xcpt & FP_UNDERFLOW) << 3 |
1978 (xcpt & FP_OVERFLOW) << 1 |
1979 (xcpt & FP_DIV0) >> 1 |
1980 (xcpt & FP_INVALID) >> 4;
1981}
1982
thsc904ef02008-07-23 16:16:31 +00001983static inline void update_fcr31(void)
thsfd4a04e2007-05-18 11:55:54 +00001984{
thsf01be152008-09-18 11:57:27 +00001985 int tmp = ieee_ex_to_mips(get_float_exception_flags(&env->active_fpu.fp_status));
thsfd4a04e2007-05-18 11:55:54 +00001986
thsf01be152008-09-18 11:57:27 +00001987 SET_FP_CAUSE(env->active_fpu.fcr31, tmp);
1988 if (GET_FP_ENABLE(env->active_fpu.fcr31) & tmp)
aurel32c01fccd2009-03-08 00:06:01 +00001989 helper_raise_exception(EXCP_FPE);
thsfd4a04e2007-05-18 11:55:54 +00001990 else
thsf01be152008-09-18 11:57:27 +00001991 UPDATE_FP_FLAGS(env->active_fpu.fcr31, tmp);
thsfd4a04e2007-05-18 11:55:54 +00001992}
1993
thsa16336e2008-06-19 18:35:02 +00001994/* Float support.
1995 Single precition routines have a "s" suffix, double precision a
1996 "d" suffix, 32bit integer "w", 64bit integer "l", paired single "ps",
1997 paired single lower "pl", paired single upper "pu". */
1998
thsa16336e2008-06-19 18:35:02 +00001999/* unary operations, modifying fp status */
aurel32c01fccd2009-03-08 00:06:01 +00002000uint64_t helper_float_sqrt_d(uint64_t fdt0)
thsfd4a04e2007-05-18 11:55:54 +00002001{
thsf01be152008-09-18 11:57:27 +00002002 return float64_sqrt(fdt0, &env->active_fpu.fp_status);
thsfd4a04e2007-05-18 11:55:54 +00002003}
2004
aurel32c01fccd2009-03-08 00:06:01 +00002005uint32_t helper_float_sqrt_s(uint32_t fst0)
thsfd4a04e2007-05-18 11:55:54 +00002006{
thsf01be152008-09-18 11:57:27 +00002007 return float32_sqrt(fst0, &env->active_fpu.fp_status);
thsfd4a04e2007-05-18 11:55:54 +00002008}
2009
aurel32c01fccd2009-03-08 00:06:01 +00002010uint64_t helper_float_cvtd_s(uint32_t fst0)
thsfd4a04e2007-05-18 11:55:54 +00002011{
thsb6d96be2008-07-09 11:05:10 +00002012 uint64_t fdt2;
2013
thsf01be152008-09-18 11:57:27 +00002014 set_float_exception_flags(0, &env->active_fpu.fp_status);
2015 fdt2 = float32_to_float64(fst0, &env->active_fpu.fp_status);
thsb6d96be2008-07-09 11:05:10 +00002016 update_fcr31();
2017 return fdt2;
2018}
2019
aurel32c01fccd2009-03-08 00:06:01 +00002020uint64_t helper_float_cvtd_w(uint32_t wt0)
thsb6d96be2008-07-09 11:05:10 +00002021{
2022 uint64_t fdt2;
2023
thsf01be152008-09-18 11:57:27 +00002024 set_float_exception_flags(0, &env->active_fpu.fp_status);
2025 fdt2 = int32_to_float64(wt0, &env->active_fpu.fp_status);
thsb6d96be2008-07-09 11:05:10 +00002026 update_fcr31();
2027 return fdt2;
2028}
2029
aurel32c01fccd2009-03-08 00:06:01 +00002030uint64_t helper_float_cvtd_l(uint64_t dt0)
thsb6d96be2008-07-09 11:05:10 +00002031{
2032 uint64_t fdt2;
2033
thsf01be152008-09-18 11:57:27 +00002034 set_float_exception_flags(0, &env->active_fpu.fp_status);
2035 fdt2 = int64_to_float64(dt0, &env->active_fpu.fp_status);
thsb6d96be2008-07-09 11:05:10 +00002036 update_fcr31();
2037 return fdt2;
2038}
2039
aurel32c01fccd2009-03-08 00:06:01 +00002040uint64_t helper_float_cvtl_d(uint64_t fdt0)
thsb6d96be2008-07-09 11:05:10 +00002041{
2042 uint64_t dt2;
2043
thsf01be152008-09-18 11:57:27 +00002044 set_float_exception_flags(0, &env->active_fpu.fp_status);
2045 dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
thsb6d96be2008-07-09 11:05:10 +00002046 update_fcr31();
thsf01be152008-09-18 11:57:27 +00002047 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
thsb6d96be2008-07-09 11:05:10 +00002048 dt2 = FLOAT_SNAN64;
2049 return dt2;
2050}
2051
aurel32c01fccd2009-03-08 00:06:01 +00002052uint64_t helper_float_cvtl_s(uint32_t fst0)
thsb6d96be2008-07-09 11:05:10 +00002053{
2054 uint64_t dt2;
2055
thsf01be152008-09-18 11:57:27 +00002056 set_float_exception_flags(0, &env->active_fpu.fp_status);
2057 dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
thsb6d96be2008-07-09 11:05:10 +00002058 update_fcr31();
thsf01be152008-09-18 11:57:27 +00002059 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
thsb6d96be2008-07-09 11:05:10 +00002060 dt2 = FLOAT_SNAN64;
2061 return dt2;
2062}
2063
aurel32c01fccd2009-03-08 00:06:01 +00002064uint64_t helper_float_cvtps_pw(uint64_t dt0)
thsb6d96be2008-07-09 11:05:10 +00002065{
2066 uint32_t fst2;
2067 uint32_t fsth2;
2068
thsf01be152008-09-18 11:57:27 +00002069 set_float_exception_flags(0, &env->active_fpu.fp_status);
2070 fst2 = int32_to_float32(dt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
2071 fsth2 = int32_to_float32(dt0 >> 32, &env->active_fpu.fp_status);
thsb6d96be2008-07-09 11:05:10 +00002072 update_fcr31();
2073 return ((uint64_t)fsth2 << 32) | fst2;
2074}
2075
aurel32c01fccd2009-03-08 00:06:01 +00002076uint64_t helper_float_cvtpw_ps(uint64_t fdt0)
thsb6d96be2008-07-09 11:05:10 +00002077{
2078 uint32_t wt2;
2079 uint32_t wth2;
2080
thsf01be152008-09-18 11:57:27 +00002081 set_float_exception_flags(0, &env->active_fpu.fp_status);
2082 wt2 = float32_to_int32(fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
2083 wth2 = float32_to_int32(fdt0 >> 32, &env->active_fpu.fp_status);
thsb6d96be2008-07-09 11:05:10 +00002084 update_fcr31();
thsf01be152008-09-18 11:57:27 +00002085 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) {
thsb6d96be2008-07-09 11:05:10 +00002086 wt2 = FLOAT_SNAN32;
2087 wth2 = FLOAT_SNAN32;
2088 }
2089 return ((uint64_t)wth2 << 32) | wt2;
2090}
2091
aurel32c01fccd2009-03-08 00:06:01 +00002092uint32_t helper_float_cvts_d(uint64_t fdt0)
thsb6d96be2008-07-09 11:05:10 +00002093{
2094 uint32_t fst2;
2095
thsf01be152008-09-18 11:57:27 +00002096 set_float_exception_flags(0, &env->active_fpu.fp_status);
2097 fst2 = float64_to_float32(fdt0, &env->active_fpu.fp_status);
thsb6d96be2008-07-09 11:05:10 +00002098 update_fcr31();
2099 return fst2;
2100}
2101
aurel32c01fccd2009-03-08 00:06:01 +00002102uint32_t helper_float_cvts_w(uint32_t wt0)
thsb6d96be2008-07-09 11:05:10 +00002103{
2104 uint32_t fst2;
2105
thsf01be152008-09-18 11:57:27 +00002106 set_float_exception_flags(0, &env->active_fpu.fp_status);
2107 fst2 = int32_to_float32(wt0, &env->active_fpu.fp_status);
thsb6d96be2008-07-09 11:05:10 +00002108 update_fcr31();
2109 return fst2;
2110}
2111
aurel32c01fccd2009-03-08 00:06:01 +00002112uint32_t helper_float_cvts_l(uint64_t dt0)
thsb6d96be2008-07-09 11:05:10 +00002113{
2114 uint32_t fst2;
2115
thsf01be152008-09-18 11:57:27 +00002116 set_float_exception_flags(0, &env->active_fpu.fp_status);
2117 fst2 = int64_to_float32(dt0, &env->active_fpu.fp_status);
thsb6d96be2008-07-09 11:05:10 +00002118 update_fcr31();
2119 return fst2;
2120}
2121
aurel32c01fccd2009-03-08 00:06:01 +00002122uint32_t helper_float_cvts_pl(uint32_t wt0)
thsb6d96be2008-07-09 11:05:10 +00002123{
2124 uint32_t wt2;
2125
thsf01be152008-09-18 11:57:27 +00002126 set_float_exception_flags(0, &env->active_fpu.fp_status);
thsb6d96be2008-07-09 11:05:10 +00002127 wt2 = wt0;
2128 update_fcr31();
2129 return wt2;
2130}
2131
aurel32c01fccd2009-03-08 00:06:01 +00002132uint32_t helper_float_cvts_pu(uint32_t wth0)
thsb6d96be2008-07-09 11:05:10 +00002133{
2134 uint32_t wt2;
2135
thsf01be152008-09-18 11:57:27 +00002136 set_float_exception_flags(0, &env->active_fpu.fp_status);
thsb6d96be2008-07-09 11:05:10 +00002137 wt2 = wth0;
2138 update_fcr31();
2139 return wt2;
2140}
2141
aurel32c01fccd2009-03-08 00:06:01 +00002142uint32_t helper_float_cvtw_s(uint32_t fst0)
thsb6d96be2008-07-09 11:05:10 +00002143{
2144 uint32_t wt2;
2145
thsf01be152008-09-18 11:57:27 +00002146 set_float_exception_flags(0, &env->active_fpu.fp_status);
2147 wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
thsb6d96be2008-07-09 11:05:10 +00002148 update_fcr31();
thsf01be152008-09-18 11:57:27 +00002149 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
thsb6d96be2008-07-09 11:05:10 +00002150 wt2 = FLOAT_SNAN32;
2151 return wt2;
2152}
2153
aurel32c01fccd2009-03-08 00:06:01 +00002154uint32_t helper_float_cvtw_d(uint64_t fdt0)
thsb6d96be2008-07-09 11:05:10 +00002155{
2156 uint32_t wt2;
2157
thsf01be152008-09-18 11:57:27 +00002158 set_float_exception_flags(0, &env->active_fpu.fp_status);
2159 wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
thsb6d96be2008-07-09 11:05:10 +00002160 update_fcr31();
thsf01be152008-09-18 11:57:27 +00002161 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
thsb6d96be2008-07-09 11:05:10 +00002162 wt2 = FLOAT_SNAN32;
2163 return wt2;
2164}
2165
aurel32c01fccd2009-03-08 00:06:01 +00002166uint64_t helper_float_roundl_d(uint64_t fdt0)
thsb6d96be2008-07-09 11:05:10 +00002167{
2168 uint64_t dt2;
2169
thsf01be152008-09-18 11:57:27 +00002170 set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2171 dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
thsfd4a04e2007-05-18 11:55:54 +00002172 RESTORE_ROUNDING_MODE;
2173 update_fcr31();
thsf01be152008-09-18 11:57:27 +00002174 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
thsb6d96be2008-07-09 11:05:10 +00002175 dt2 = FLOAT_SNAN64;
2176 return dt2;
thsfd4a04e2007-05-18 11:55:54 +00002177}
2178
aurel32c01fccd2009-03-08 00:06:01 +00002179uint64_t helper_float_roundl_s(uint32_t fst0)
thsfd4a04e2007-05-18 11:55:54 +00002180{
thsb6d96be2008-07-09 11:05:10 +00002181 uint64_t dt2;
2182
thsf01be152008-09-18 11:57:27 +00002183 set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2184 dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
thsb6d96be2008-07-09 11:05:10 +00002185 RESTORE_ROUNDING_MODE;
thsfd4a04e2007-05-18 11:55:54 +00002186 update_fcr31();
thsf01be152008-09-18 11:57:27 +00002187 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
thsb6d96be2008-07-09 11:05:10 +00002188 dt2 = FLOAT_SNAN64;
2189 return dt2;
thsfd4a04e2007-05-18 11:55:54 +00002190}
2191
aurel32c01fccd2009-03-08 00:06:01 +00002192uint32_t helper_float_roundw_d(uint64_t fdt0)
thsfd4a04e2007-05-18 11:55:54 +00002193{
thsb6d96be2008-07-09 11:05:10 +00002194 uint32_t wt2;
2195
thsf01be152008-09-18 11:57:27 +00002196 set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2197 wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
thsfd4a04e2007-05-18 11:55:54 +00002198 RESTORE_ROUNDING_MODE;
2199 update_fcr31();
thsf01be152008-09-18 11:57:27 +00002200 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
thsb6d96be2008-07-09 11:05:10 +00002201 wt2 = FLOAT_SNAN32;
2202 return wt2;
thsfd4a04e2007-05-18 11:55:54 +00002203}
2204
aurel32c01fccd2009-03-08 00:06:01 +00002205uint32_t helper_float_roundw_s(uint32_t fst0)
thsfd4a04e2007-05-18 11:55:54 +00002206{
thsb6d96be2008-07-09 11:05:10 +00002207 uint32_t wt2;
2208
thsf01be152008-09-18 11:57:27 +00002209 set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2210 wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
thsfd4a04e2007-05-18 11:55:54 +00002211 RESTORE_ROUNDING_MODE;
2212 update_fcr31();
thsf01be152008-09-18 11:57:27 +00002213 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
thsb6d96be2008-07-09 11:05:10 +00002214 wt2 = FLOAT_SNAN32;
2215 return wt2;
thsfd4a04e2007-05-18 11:55:54 +00002216}
thsb6d96be2008-07-09 11:05:10 +00002217
aurel32c01fccd2009-03-08 00:06:01 +00002218uint64_t helper_float_truncl_d(uint64_t fdt0)
thsfd4a04e2007-05-18 11:55:54 +00002219{
thsb6d96be2008-07-09 11:05:10 +00002220 uint64_t dt2;
2221
thsf01be152008-09-18 11:57:27 +00002222 dt2 = float64_to_int64_round_to_zero(fdt0, &env->active_fpu.fp_status);
thsfd4a04e2007-05-18 11:55:54 +00002223 update_fcr31();
thsf01be152008-09-18 11:57:27 +00002224 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
thsb6d96be2008-07-09 11:05:10 +00002225 dt2 = FLOAT_SNAN64;
2226 return dt2;
thsfd4a04e2007-05-18 11:55:54 +00002227}
thsb6d96be2008-07-09 11:05:10 +00002228
aurel32c01fccd2009-03-08 00:06:01 +00002229uint64_t helper_float_truncl_s(uint32_t fst0)
thsfd4a04e2007-05-18 11:55:54 +00002230{
thsb6d96be2008-07-09 11:05:10 +00002231 uint64_t dt2;
2232
thsf01be152008-09-18 11:57:27 +00002233 dt2 = float32_to_int64_round_to_zero(fst0, &env->active_fpu.fp_status);
thsfd4a04e2007-05-18 11:55:54 +00002234 update_fcr31();
thsf01be152008-09-18 11:57:27 +00002235 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
thsb6d96be2008-07-09 11:05:10 +00002236 dt2 = FLOAT_SNAN64;
2237 return dt2;
thsfd4a04e2007-05-18 11:55:54 +00002238}
thsb6d96be2008-07-09 11:05:10 +00002239
aurel32c01fccd2009-03-08 00:06:01 +00002240uint32_t helper_float_truncw_d(uint64_t fdt0)
thsfd4a04e2007-05-18 11:55:54 +00002241{
thsb6d96be2008-07-09 11:05:10 +00002242 uint32_t wt2;
2243
thsf01be152008-09-18 11:57:27 +00002244 wt2 = float64_to_int32_round_to_zero(fdt0, &env->active_fpu.fp_status);
thsb6d96be2008-07-09 11:05:10 +00002245 update_fcr31();
thsf01be152008-09-18 11:57:27 +00002246 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
thsb6d96be2008-07-09 11:05:10 +00002247 wt2 = FLOAT_SNAN32;
2248 return wt2;
2249}
2250
aurel32c01fccd2009-03-08 00:06:01 +00002251uint32_t helper_float_truncw_s(uint32_t fst0)
thsb6d96be2008-07-09 11:05:10 +00002252{
2253 uint32_t wt2;
2254
thsf01be152008-09-18 11:57:27 +00002255 wt2 = float32_to_int32_round_to_zero(fst0, &env->active_fpu.fp_status);
thsb6d96be2008-07-09 11:05:10 +00002256 update_fcr31();
thsf01be152008-09-18 11:57:27 +00002257 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
thsb6d96be2008-07-09 11:05:10 +00002258 wt2 = FLOAT_SNAN32;
2259 return wt2;
2260}
2261
aurel32c01fccd2009-03-08 00:06:01 +00002262uint64_t helper_float_ceill_d(uint64_t fdt0)
thsb6d96be2008-07-09 11:05:10 +00002263{
2264 uint64_t dt2;
2265
thsf01be152008-09-18 11:57:27 +00002266 set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
2267 dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
thsfd4a04e2007-05-18 11:55:54 +00002268 RESTORE_ROUNDING_MODE;
2269 update_fcr31();
thsf01be152008-09-18 11:57:27 +00002270 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
thsb6d96be2008-07-09 11:05:10 +00002271 dt2 = FLOAT_SNAN64;
2272 return dt2;
2273}
2274
aurel32c01fccd2009-03-08 00:06:01 +00002275uint64_t helper_float_ceill_s(uint32_t fst0)
thsb6d96be2008-07-09 11:05:10 +00002276{
2277 uint64_t dt2;
2278
thsf01be152008-09-18 11:57:27 +00002279 set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
2280 dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
thsb6d96be2008-07-09 11:05:10 +00002281 RESTORE_ROUNDING_MODE;
2282 update_fcr31();
thsf01be152008-09-18 11:57:27 +00002283 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
thsb6d96be2008-07-09 11:05:10 +00002284 dt2 = FLOAT_SNAN64;
2285 return dt2;
2286}
2287
aurel32c01fccd2009-03-08 00:06:01 +00002288uint32_t helper_float_ceilw_d(uint64_t fdt0)
thsb6d96be2008-07-09 11:05:10 +00002289{
2290 uint32_t wt2;
2291
thsf01be152008-09-18 11:57:27 +00002292 set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
2293 wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
thsb6d96be2008-07-09 11:05:10 +00002294 RESTORE_ROUNDING_MODE;
2295 update_fcr31();
thsf01be152008-09-18 11:57:27 +00002296 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
thsb6d96be2008-07-09 11:05:10 +00002297 wt2 = FLOAT_SNAN32;
2298 return wt2;
2299}
2300
aurel32c01fccd2009-03-08 00:06:01 +00002301uint32_t helper_float_ceilw_s(uint32_t fst0)
thsb6d96be2008-07-09 11:05:10 +00002302{
2303 uint32_t wt2;
2304
thsf01be152008-09-18 11:57:27 +00002305 set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
2306 wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
thsb6d96be2008-07-09 11:05:10 +00002307 RESTORE_ROUNDING_MODE;
2308 update_fcr31();
thsf01be152008-09-18 11:57:27 +00002309 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
thsb6d96be2008-07-09 11:05:10 +00002310 wt2 = FLOAT_SNAN32;
2311 return wt2;
2312}
2313
aurel32c01fccd2009-03-08 00:06:01 +00002314uint64_t helper_float_floorl_d(uint64_t fdt0)
thsb6d96be2008-07-09 11:05:10 +00002315{
2316 uint64_t dt2;
2317
thsf01be152008-09-18 11:57:27 +00002318 set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
2319 dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
thsb6d96be2008-07-09 11:05:10 +00002320 RESTORE_ROUNDING_MODE;
2321 update_fcr31();
thsf01be152008-09-18 11:57:27 +00002322 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
thsb6d96be2008-07-09 11:05:10 +00002323 dt2 = FLOAT_SNAN64;
2324 return dt2;
2325}
2326
aurel32c01fccd2009-03-08 00:06:01 +00002327uint64_t helper_float_floorl_s(uint32_t fst0)
thsb6d96be2008-07-09 11:05:10 +00002328{
2329 uint64_t dt2;
2330
thsf01be152008-09-18 11:57:27 +00002331 set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
2332 dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
thsb6d96be2008-07-09 11:05:10 +00002333 RESTORE_ROUNDING_MODE;
2334 update_fcr31();
thsf01be152008-09-18 11:57:27 +00002335 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
thsb6d96be2008-07-09 11:05:10 +00002336 dt2 = FLOAT_SNAN64;
2337 return dt2;
2338}
2339
aurel32c01fccd2009-03-08 00:06:01 +00002340uint32_t helper_float_floorw_d(uint64_t fdt0)
thsb6d96be2008-07-09 11:05:10 +00002341{
2342 uint32_t wt2;
2343
thsf01be152008-09-18 11:57:27 +00002344 set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
2345 wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
thsb6d96be2008-07-09 11:05:10 +00002346 RESTORE_ROUNDING_MODE;
2347 update_fcr31();
thsf01be152008-09-18 11:57:27 +00002348 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
thsb6d96be2008-07-09 11:05:10 +00002349 wt2 = FLOAT_SNAN32;
2350 return wt2;
2351}
2352
aurel32c01fccd2009-03-08 00:06:01 +00002353uint32_t helper_float_floorw_s(uint32_t fst0)
thsb6d96be2008-07-09 11:05:10 +00002354{
2355 uint32_t wt2;
2356
thsf01be152008-09-18 11:57:27 +00002357 set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
2358 wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
thsb6d96be2008-07-09 11:05:10 +00002359 RESTORE_ROUNDING_MODE;
2360 update_fcr31();
thsf01be152008-09-18 11:57:27 +00002361 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
thsb6d96be2008-07-09 11:05:10 +00002362 wt2 = FLOAT_SNAN32;
2363 return wt2;
thsfd4a04e2007-05-18 11:55:54 +00002364}
2365
thsa16336e2008-06-19 18:35:02 +00002366/* unary operations, not modifying fp status */
thsb6d96be2008-07-09 11:05:10 +00002367#define FLOAT_UNOP(name) \
aurel32c01fccd2009-03-08 00:06:01 +00002368uint64_t helper_float_ ## name ## _d(uint64_t fdt0) \
thsb6d96be2008-07-09 11:05:10 +00002369{ \
2370 return float64_ ## name(fdt0); \
2371} \
aurel32c01fccd2009-03-08 00:06:01 +00002372uint32_t helper_float_ ## name ## _s(uint32_t fst0) \
thsb6d96be2008-07-09 11:05:10 +00002373{ \
2374 return float32_ ## name(fst0); \
2375} \
aurel32c01fccd2009-03-08 00:06:01 +00002376uint64_t helper_float_ ## name ## _ps(uint64_t fdt0) \
thsb6d96be2008-07-09 11:05:10 +00002377{ \
2378 uint32_t wt0; \
2379 uint32_t wth0; \
2380 \
2381 wt0 = float32_ ## name(fdt0 & 0XFFFFFFFF); \
2382 wth0 = float32_ ## name(fdt0 >> 32); \
2383 return ((uint64_t)wth0 << 32) | wt0; \
thsa16336e2008-06-19 18:35:02 +00002384}
2385FLOAT_UNOP(abs)
2386FLOAT_UNOP(chs)
2387#undef FLOAT_UNOP
2388
ths8dfdb872007-06-26 20:26:03 +00002389/* MIPS specific unary operations */
aurel32c01fccd2009-03-08 00:06:01 +00002390uint64_t helper_float_recip_d(uint64_t fdt0)
ths8dfdb872007-06-26 20:26:03 +00002391{
thsb6d96be2008-07-09 11:05:10 +00002392 uint64_t fdt2;
2393
thsf01be152008-09-18 11:57:27 +00002394 set_float_exception_flags(0, &env->active_fpu.fp_status);
2395 fdt2 = float64_div(FLOAT_ONE64, fdt0, &env->active_fpu.fp_status);
ths8dfdb872007-06-26 20:26:03 +00002396 update_fcr31();
thsb6d96be2008-07-09 11:05:10 +00002397 return fdt2;
ths8dfdb872007-06-26 20:26:03 +00002398}
ths57fa1fb2007-05-19 20:29:41 +00002399
aurel32c01fccd2009-03-08 00:06:01 +00002400uint32_t helper_float_recip_s(uint32_t fst0)
ths8dfdb872007-06-26 20:26:03 +00002401{
thsb6d96be2008-07-09 11:05:10 +00002402 uint32_t fst2;
2403
thsf01be152008-09-18 11:57:27 +00002404 set_float_exception_flags(0, &env->active_fpu.fp_status);
2405 fst2 = float32_div(FLOAT_ONE32, fst0, &env->active_fpu.fp_status);
ths8dfdb872007-06-26 20:26:03 +00002406 update_fcr31();
thsb6d96be2008-07-09 11:05:10 +00002407 return fst2;
ths8dfdb872007-06-26 20:26:03 +00002408}
2409
aurel32c01fccd2009-03-08 00:06:01 +00002410uint64_t helper_float_rsqrt_d(uint64_t fdt0)
ths8dfdb872007-06-26 20:26:03 +00002411{
thsb6d96be2008-07-09 11:05:10 +00002412 uint64_t fdt2;
2413
thsf01be152008-09-18 11:57:27 +00002414 set_float_exception_flags(0, &env->active_fpu.fp_status);
2415 fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
2416 fdt2 = float64_div(FLOAT_ONE64, fdt2, &env->active_fpu.fp_status);
ths8dfdb872007-06-26 20:26:03 +00002417 update_fcr31();
thsb6d96be2008-07-09 11:05:10 +00002418 return fdt2;
ths8dfdb872007-06-26 20:26:03 +00002419}
2420
aurel32c01fccd2009-03-08 00:06:01 +00002421uint32_t helper_float_rsqrt_s(uint32_t fst0)
ths8dfdb872007-06-26 20:26:03 +00002422{
thsb6d96be2008-07-09 11:05:10 +00002423 uint32_t fst2;
2424
thsf01be152008-09-18 11:57:27 +00002425 set_float_exception_flags(0, &env->active_fpu.fp_status);
2426 fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status);
2427 fst2 = float32_div(FLOAT_ONE32, fst2, &env->active_fpu.fp_status);
ths8dfdb872007-06-26 20:26:03 +00002428 update_fcr31();
thsb6d96be2008-07-09 11:05:10 +00002429 return fst2;
ths8dfdb872007-06-26 20:26:03 +00002430}
thsb6d96be2008-07-09 11:05:10 +00002431
aurel32c01fccd2009-03-08 00:06:01 +00002432uint64_t helper_float_recip1_d(uint64_t fdt0)
ths8dfdb872007-06-26 20:26:03 +00002433{
thsb6d96be2008-07-09 11:05:10 +00002434 uint64_t fdt2;
2435
thsf01be152008-09-18 11:57:27 +00002436 set_float_exception_flags(0, &env->active_fpu.fp_status);
2437 fdt2 = float64_div(FLOAT_ONE64, fdt0, &env->active_fpu.fp_status);
ths8dfdb872007-06-26 20:26:03 +00002438 update_fcr31();
thsb6d96be2008-07-09 11:05:10 +00002439 return fdt2;
ths8dfdb872007-06-26 20:26:03 +00002440}
thsb6d96be2008-07-09 11:05:10 +00002441
aurel32c01fccd2009-03-08 00:06:01 +00002442uint32_t helper_float_recip1_s(uint32_t fst0)
ths8dfdb872007-06-26 20:26:03 +00002443{
thsb6d96be2008-07-09 11:05:10 +00002444 uint32_t fst2;
2445
thsf01be152008-09-18 11:57:27 +00002446 set_float_exception_flags(0, &env->active_fpu.fp_status);
2447 fst2 = float32_div(FLOAT_ONE32, fst0, &env->active_fpu.fp_status);
ths8dfdb872007-06-26 20:26:03 +00002448 update_fcr31();
thsb6d96be2008-07-09 11:05:10 +00002449 return fst2;
ths8dfdb872007-06-26 20:26:03 +00002450}
ths57fa1fb2007-05-19 20:29:41 +00002451
aurel32c01fccd2009-03-08 00:06:01 +00002452uint64_t helper_float_recip1_ps(uint64_t fdt0)
thsb6d96be2008-07-09 11:05:10 +00002453{
2454 uint32_t fst2;
2455 uint32_t fsth2;
2456
thsf01be152008-09-18 11:57:27 +00002457 set_float_exception_flags(0, &env->active_fpu.fp_status);
2458 fst2 = float32_div(FLOAT_ONE32, fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
2459 fsth2 = float32_div(FLOAT_ONE32, fdt0 >> 32, &env->active_fpu.fp_status);
thsb6d96be2008-07-09 11:05:10 +00002460 update_fcr31();
2461 return ((uint64_t)fsth2 << 32) | fst2;
2462}
2463
aurel32c01fccd2009-03-08 00:06:01 +00002464uint64_t helper_float_rsqrt1_d(uint64_t fdt0)
thsb6d96be2008-07-09 11:05:10 +00002465{
2466 uint64_t fdt2;
2467
thsf01be152008-09-18 11:57:27 +00002468 set_float_exception_flags(0, &env->active_fpu.fp_status);
2469 fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
2470 fdt2 = float64_div(FLOAT_ONE64, fdt2, &env->active_fpu.fp_status);
thsb6d96be2008-07-09 11:05:10 +00002471 update_fcr31();
2472 return fdt2;
2473}
2474
aurel32c01fccd2009-03-08 00:06:01 +00002475uint32_t helper_float_rsqrt1_s(uint32_t fst0)
thsb6d96be2008-07-09 11:05:10 +00002476{
2477 uint32_t fst2;
2478
thsf01be152008-09-18 11:57:27 +00002479 set_float_exception_flags(0, &env->active_fpu.fp_status);
2480 fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status);
2481 fst2 = float32_div(FLOAT_ONE32, fst2, &env->active_fpu.fp_status);
thsb6d96be2008-07-09 11:05:10 +00002482 update_fcr31();
2483 return fst2;
2484}
2485
aurel32c01fccd2009-03-08 00:06:01 +00002486uint64_t helper_float_rsqrt1_ps(uint64_t fdt0)
thsb6d96be2008-07-09 11:05:10 +00002487{
2488 uint32_t fst2;
2489 uint32_t fsth2;
2490
thsf01be152008-09-18 11:57:27 +00002491 set_float_exception_flags(0, &env->active_fpu.fp_status);
2492 fst2 = float32_sqrt(fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
2493 fsth2 = float32_sqrt(fdt0 >> 32, &env->active_fpu.fp_status);
2494 fst2 = float32_div(FLOAT_ONE32, fst2, &env->active_fpu.fp_status);
2495 fsth2 = float32_div(FLOAT_ONE32, fsth2, &env->active_fpu.fp_status);
thsb6d96be2008-07-09 11:05:10 +00002496 update_fcr31();
2497 return ((uint64_t)fsth2 << 32) | fst2;
2498}
2499
aurel32c01fccd2009-03-08 00:06:01 +00002500#define FLOAT_OP(name, p) void helper_float_##name##_##p(void)
thsb6d96be2008-07-09 11:05:10 +00002501
thsfd4a04e2007-05-18 11:55:54 +00002502/* binary operations */
thsb6d96be2008-07-09 11:05:10 +00002503#define FLOAT_BINOP(name) \
aurel32c01fccd2009-03-08 00:06:01 +00002504uint64_t helper_float_ ## name ## _d(uint64_t fdt0, uint64_t fdt1) \
thsb6d96be2008-07-09 11:05:10 +00002505{ \
2506 uint64_t dt2; \
2507 \
thsf01be152008-09-18 11:57:27 +00002508 set_float_exception_flags(0, &env->active_fpu.fp_status); \
2509 dt2 = float64_ ## name (fdt0, fdt1, &env->active_fpu.fp_status); \
thsead93602007-09-06 00:18:15 +00002510 update_fcr31(); \
thsf01be152008-09-18 11:57:27 +00002511 if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_INVALID) \
thsb6d96be2008-07-09 11:05:10 +00002512 dt2 = FLOAT_QNAN64; \
2513 return dt2; \
2514} \
2515 \
aurel32c01fccd2009-03-08 00:06:01 +00002516uint32_t helper_float_ ## name ## _s(uint32_t fst0, uint32_t fst1) \
thsb6d96be2008-07-09 11:05:10 +00002517{ \
2518 uint32_t wt2; \
2519 \
thsf01be152008-09-18 11:57:27 +00002520 set_float_exception_flags(0, &env->active_fpu.fp_status); \
2521 wt2 = float32_ ## name (fst0, fst1, &env->active_fpu.fp_status); \
thsead93602007-09-06 00:18:15 +00002522 update_fcr31(); \
thsf01be152008-09-18 11:57:27 +00002523 if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_INVALID) \
thsb6d96be2008-07-09 11:05:10 +00002524 wt2 = FLOAT_QNAN32; \
2525 return wt2; \
2526} \
2527 \
aurel32c01fccd2009-03-08 00:06:01 +00002528uint64_t helper_float_ ## name ## _ps(uint64_t fdt0, uint64_t fdt1) \
thsb6d96be2008-07-09 11:05:10 +00002529{ \
2530 uint32_t fst0 = fdt0 & 0XFFFFFFFF; \
2531 uint32_t fsth0 = fdt0 >> 32; \
2532 uint32_t fst1 = fdt1 & 0XFFFFFFFF; \
2533 uint32_t fsth1 = fdt1 >> 32; \
2534 uint32_t wt2; \
2535 uint32_t wth2; \
2536 \
thsf01be152008-09-18 11:57:27 +00002537 set_float_exception_flags(0, &env->active_fpu.fp_status); \
2538 wt2 = float32_ ## name (fst0, fst1, &env->active_fpu.fp_status); \
2539 wth2 = float32_ ## name (fsth0, fsth1, &env->active_fpu.fp_status); \
thsb6d96be2008-07-09 11:05:10 +00002540 update_fcr31(); \
thsf01be152008-09-18 11:57:27 +00002541 if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_INVALID) { \
thsb6d96be2008-07-09 11:05:10 +00002542 wt2 = FLOAT_QNAN32; \
2543 wth2 = FLOAT_QNAN32; \
2544 } \
2545 return ((uint64_t)wth2 << 32) | wt2; \
thsfd4a04e2007-05-18 11:55:54 +00002546}
thsb6d96be2008-07-09 11:05:10 +00002547
thsfd4a04e2007-05-18 11:55:54 +00002548FLOAT_BINOP(add)
2549FLOAT_BINOP(sub)
2550FLOAT_BINOP(mul)
2551FLOAT_BINOP(div)
2552#undef FLOAT_BINOP
2553
thsa16336e2008-06-19 18:35:02 +00002554/* ternary operations */
thsb6d96be2008-07-09 11:05:10 +00002555#define FLOAT_TERNOP(name1, name2) \
aurel32c01fccd2009-03-08 00:06:01 +00002556uint64_t helper_float_ ## name1 ## name2 ## _d(uint64_t fdt0, uint64_t fdt1, \
thsb6d96be2008-07-09 11:05:10 +00002557 uint64_t fdt2) \
2558{ \
thsf01be152008-09-18 11:57:27 +00002559 fdt0 = float64_ ## name1 (fdt0, fdt1, &env->active_fpu.fp_status); \
2560 return float64_ ## name2 (fdt0, fdt2, &env->active_fpu.fp_status); \
thsb6d96be2008-07-09 11:05:10 +00002561} \
2562 \
aurel32c01fccd2009-03-08 00:06:01 +00002563uint32_t helper_float_ ## name1 ## name2 ## _s(uint32_t fst0, uint32_t fst1, \
thsb6d96be2008-07-09 11:05:10 +00002564 uint32_t fst2) \
2565{ \
thsf01be152008-09-18 11:57:27 +00002566 fst0 = float32_ ## name1 (fst0, fst1, &env->active_fpu.fp_status); \
2567 return float32_ ## name2 (fst0, fst2, &env->active_fpu.fp_status); \
thsb6d96be2008-07-09 11:05:10 +00002568} \
2569 \
aurel32c01fccd2009-03-08 00:06:01 +00002570uint64_t helper_float_ ## name1 ## name2 ## _ps(uint64_t fdt0, uint64_t fdt1, \
thsb6d96be2008-07-09 11:05:10 +00002571 uint64_t fdt2) \
2572{ \
2573 uint32_t fst0 = fdt0 & 0XFFFFFFFF; \
2574 uint32_t fsth0 = fdt0 >> 32; \
2575 uint32_t fst1 = fdt1 & 0XFFFFFFFF; \
2576 uint32_t fsth1 = fdt1 >> 32; \
2577 uint32_t fst2 = fdt2 & 0XFFFFFFFF; \
2578 uint32_t fsth2 = fdt2 >> 32; \
2579 \
thsf01be152008-09-18 11:57:27 +00002580 fst0 = float32_ ## name1 (fst0, fst1, &env->active_fpu.fp_status); \
2581 fsth0 = float32_ ## name1 (fsth0, fsth1, &env->active_fpu.fp_status); \
2582 fst2 = float32_ ## name2 (fst0, fst2, &env->active_fpu.fp_status); \
2583 fsth2 = float32_ ## name2 (fsth0, fsth2, &env->active_fpu.fp_status); \
thsb6d96be2008-07-09 11:05:10 +00002584 return ((uint64_t)fsth2 << 32) | fst2; \
thsa16336e2008-06-19 18:35:02 +00002585}
thsb6d96be2008-07-09 11:05:10 +00002586
thsa16336e2008-06-19 18:35:02 +00002587FLOAT_TERNOP(mul, add)
2588FLOAT_TERNOP(mul, sub)
2589#undef FLOAT_TERNOP
2590
2591/* negated ternary operations */
thsb6d96be2008-07-09 11:05:10 +00002592#define FLOAT_NTERNOP(name1, name2) \
aurel32c01fccd2009-03-08 00:06:01 +00002593uint64_t helper_float_n ## name1 ## name2 ## _d(uint64_t fdt0, uint64_t fdt1, \
thsb6d96be2008-07-09 11:05:10 +00002594 uint64_t fdt2) \
2595{ \
thsf01be152008-09-18 11:57:27 +00002596 fdt0 = float64_ ## name1 (fdt0, fdt1, &env->active_fpu.fp_status); \
2597 fdt2 = float64_ ## name2 (fdt0, fdt2, &env->active_fpu.fp_status); \
thsb6d96be2008-07-09 11:05:10 +00002598 return float64_chs(fdt2); \
2599} \
2600 \
aurel32c01fccd2009-03-08 00:06:01 +00002601uint32_t helper_float_n ## name1 ## name2 ## _s(uint32_t fst0, uint32_t fst1, \
thsb6d96be2008-07-09 11:05:10 +00002602 uint32_t fst2) \
2603{ \
thsf01be152008-09-18 11:57:27 +00002604 fst0 = float32_ ## name1 (fst0, fst1, &env->active_fpu.fp_status); \
2605 fst2 = float32_ ## name2 (fst0, fst2, &env->active_fpu.fp_status); \
thsb6d96be2008-07-09 11:05:10 +00002606 return float32_chs(fst2); \
2607} \
2608 \
aurel32c01fccd2009-03-08 00:06:01 +00002609uint64_t helper_float_n ## name1 ## name2 ## _ps(uint64_t fdt0, uint64_t fdt1,\
thsb6d96be2008-07-09 11:05:10 +00002610 uint64_t fdt2) \
2611{ \
2612 uint32_t fst0 = fdt0 & 0XFFFFFFFF; \
2613 uint32_t fsth0 = fdt0 >> 32; \
2614 uint32_t fst1 = fdt1 & 0XFFFFFFFF; \
2615 uint32_t fsth1 = fdt1 >> 32; \
2616 uint32_t fst2 = fdt2 & 0XFFFFFFFF; \
2617 uint32_t fsth2 = fdt2 >> 32; \
2618 \
thsf01be152008-09-18 11:57:27 +00002619 fst0 = float32_ ## name1 (fst0, fst1, &env->active_fpu.fp_status); \
2620 fsth0 = float32_ ## name1 (fsth0, fsth1, &env->active_fpu.fp_status); \
2621 fst2 = float32_ ## name2 (fst0, fst2, &env->active_fpu.fp_status); \
2622 fsth2 = float32_ ## name2 (fsth0, fsth2, &env->active_fpu.fp_status); \
thsb6d96be2008-07-09 11:05:10 +00002623 fst2 = float32_chs(fst2); \
2624 fsth2 = float32_chs(fsth2); \
2625 return ((uint64_t)fsth2 << 32) | fst2; \
thsa16336e2008-06-19 18:35:02 +00002626}
thsb6d96be2008-07-09 11:05:10 +00002627
thsa16336e2008-06-19 18:35:02 +00002628FLOAT_NTERNOP(mul, add)
2629FLOAT_NTERNOP(mul, sub)
2630#undef FLOAT_NTERNOP
2631
ths8dfdb872007-06-26 20:26:03 +00002632/* MIPS specific binary operations */
aurel32c01fccd2009-03-08 00:06:01 +00002633uint64_t helper_float_recip2_d(uint64_t fdt0, uint64_t fdt2)
ths8dfdb872007-06-26 20:26:03 +00002634{
thsf01be152008-09-18 11:57:27 +00002635 set_float_exception_flags(0, &env->active_fpu.fp_status);
2636 fdt2 = float64_mul(fdt0, fdt2, &env->active_fpu.fp_status);
2637 fdt2 = float64_chs(float64_sub(fdt2, FLOAT_ONE64, &env->active_fpu.fp_status));
ths8dfdb872007-06-26 20:26:03 +00002638 update_fcr31();
thsb6d96be2008-07-09 11:05:10 +00002639 return fdt2;
ths8dfdb872007-06-26 20:26:03 +00002640}
2641
aurel32c01fccd2009-03-08 00:06:01 +00002642uint32_t helper_float_recip2_s(uint32_t fst0, uint32_t fst2)
ths8dfdb872007-06-26 20:26:03 +00002643{
thsf01be152008-09-18 11:57:27 +00002644 set_float_exception_flags(0, &env->active_fpu.fp_status);
2645 fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
2646 fst2 = float32_chs(float32_sub(fst2, FLOAT_ONE32, &env->active_fpu.fp_status));
ths8dfdb872007-06-26 20:26:03 +00002647 update_fcr31();
thsb6d96be2008-07-09 11:05:10 +00002648 return fst2;
ths8dfdb872007-06-26 20:26:03 +00002649}
ths57fa1fb2007-05-19 20:29:41 +00002650
aurel32c01fccd2009-03-08 00:06:01 +00002651uint64_t helper_float_recip2_ps(uint64_t fdt0, uint64_t fdt2)
thsfd4a04e2007-05-18 11:55:54 +00002652{
thsb6d96be2008-07-09 11:05:10 +00002653 uint32_t fst0 = fdt0 & 0XFFFFFFFF;
2654 uint32_t fsth0 = fdt0 >> 32;
2655 uint32_t fst2 = fdt2 & 0XFFFFFFFF;
2656 uint32_t fsth2 = fdt2 >> 32;
2657
thsf01be152008-09-18 11:57:27 +00002658 set_float_exception_flags(0, &env->active_fpu.fp_status);
2659 fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
2660 fsth2 = float32_mul(fsth0, fsth2, &env->active_fpu.fp_status);
2661 fst2 = float32_chs(float32_sub(fst2, FLOAT_ONE32, &env->active_fpu.fp_status));
2662 fsth2 = float32_chs(float32_sub(fsth2, FLOAT_ONE32, &env->active_fpu.fp_status));
thsfd4a04e2007-05-18 11:55:54 +00002663 update_fcr31();
thsb6d96be2008-07-09 11:05:10 +00002664 return ((uint64_t)fsth2 << 32) | fst2;
thsfd4a04e2007-05-18 11:55:54 +00002665}
2666
aurel32c01fccd2009-03-08 00:06:01 +00002667uint64_t helper_float_rsqrt2_d(uint64_t fdt0, uint64_t fdt2)
ths57fa1fb2007-05-19 20:29:41 +00002668{
thsf01be152008-09-18 11:57:27 +00002669 set_float_exception_flags(0, &env->active_fpu.fp_status);
2670 fdt2 = float64_mul(fdt0, fdt2, &env->active_fpu.fp_status);
2671 fdt2 = float64_sub(fdt2, FLOAT_ONE64, &env->active_fpu.fp_status);
2672 fdt2 = float64_chs(float64_div(fdt2, FLOAT_TWO64, &env->active_fpu.fp_status));
ths57fa1fb2007-05-19 20:29:41 +00002673 update_fcr31();
thsb6d96be2008-07-09 11:05:10 +00002674 return fdt2;
2675}
2676
aurel32c01fccd2009-03-08 00:06:01 +00002677uint32_t helper_float_rsqrt2_s(uint32_t fst0, uint32_t fst2)
thsb6d96be2008-07-09 11:05:10 +00002678{
thsf01be152008-09-18 11:57:27 +00002679 set_float_exception_flags(0, &env->active_fpu.fp_status);
2680 fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
2681 fst2 = float32_sub(fst2, FLOAT_ONE32, &env->active_fpu.fp_status);
2682 fst2 = float32_chs(float32_div(fst2, FLOAT_TWO32, &env->active_fpu.fp_status));
thsb6d96be2008-07-09 11:05:10 +00002683 update_fcr31();
2684 return fst2;
2685}
2686
aurel32c01fccd2009-03-08 00:06:01 +00002687uint64_t helper_float_rsqrt2_ps(uint64_t fdt0, uint64_t fdt2)
thsb6d96be2008-07-09 11:05:10 +00002688{
2689 uint32_t fst0 = fdt0 & 0XFFFFFFFF;
2690 uint32_t fsth0 = fdt0 >> 32;
2691 uint32_t fst2 = fdt2 & 0XFFFFFFFF;
2692 uint32_t fsth2 = fdt2 >> 32;
2693
thsf01be152008-09-18 11:57:27 +00002694 set_float_exception_flags(0, &env->active_fpu.fp_status);
2695 fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
2696 fsth2 = float32_mul(fsth0, fsth2, &env->active_fpu.fp_status);
2697 fst2 = float32_sub(fst2, FLOAT_ONE32, &env->active_fpu.fp_status);
2698 fsth2 = float32_sub(fsth2, FLOAT_ONE32, &env->active_fpu.fp_status);
2699 fst2 = float32_chs(float32_div(fst2, FLOAT_TWO32, &env->active_fpu.fp_status));
2700 fsth2 = float32_chs(float32_div(fsth2, FLOAT_TWO32, &env->active_fpu.fp_status));
thsb6d96be2008-07-09 11:05:10 +00002701 update_fcr31();
2702 return ((uint64_t)fsth2 << 32) | fst2;
2703}
2704
aurel32c01fccd2009-03-08 00:06:01 +00002705uint64_t helper_float_addr_ps(uint64_t fdt0, uint64_t fdt1)
thsb6d96be2008-07-09 11:05:10 +00002706{
2707 uint32_t fst0 = fdt0 & 0XFFFFFFFF;
2708 uint32_t fsth0 = fdt0 >> 32;
2709 uint32_t fst1 = fdt1 & 0XFFFFFFFF;
2710 uint32_t fsth1 = fdt1 >> 32;
2711 uint32_t fst2;
2712 uint32_t fsth2;
2713
thsf01be152008-09-18 11:57:27 +00002714 set_float_exception_flags(0, &env->active_fpu.fp_status);
2715 fst2 = float32_add (fst0, fsth0, &env->active_fpu.fp_status);
2716 fsth2 = float32_add (fst1, fsth1, &env->active_fpu.fp_status);
thsb6d96be2008-07-09 11:05:10 +00002717 update_fcr31();
2718 return ((uint64_t)fsth2 << 32) | fst2;
2719}
2720
aurel32c01fccd2009-03-08 00:06:01 +00002721uint64_t helper_float_mulr_ps(uint64_t fdt0, uint64_t fdt1)
thsb6d96be2008-07-09 11:05:10 +00002722{
2723 uint32_t fst0 = fdt0 & 0XFFFFFFFF;
2724 uint32_t fsth0 = fdt0 >> 32;
2725 uint32_t fst1 = fdt1 & 0XFFFFFFFF;
2726 uint32_t fsth1 = fdt1 >> 32;
2727 uint32_t fst2;
2728 uint32_t fsth2;
2729
thsf01be152008-09-18 11:57:27 +00002730 set_float_exception_flags(0, &env->active_fpu.fp_status);
2731 fst2 = float32_mul (fst0, fsth0, &env->active_fpu.fp_status);
2732 fsth2 = float32_mul (fst1, fsth1, &env->active_fpu.fp_status);
thsb6d96be2008-07-09 11:05:10 +00002733 update_fcr31();
2734 return ((uint64_t)fsth2 << 32) | fst2;
ths57fa1fb2007-05-19 20:29:41 +00002735}
2736
ths8dfdb872007-06-26 20:26:03 +00002737/* compare operations */
thsb6d96be2008-07-09 11:05:10 +00002738#define FOP_COND_D(op, cond) \
aurel32c01fccd2009-03-08 00:06:01 +00002739void helper_cmp_d_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \
thsb6d96be2008-07-09 11:05:10 +00002740{ \
2741 int c = cond; \
2742 update_fcr31(); \
2743 if (c) \
thsf01be152008-09-18 11:57:27 +00002744 SET_FP_COND(cc, env->active_fpu); \
thsb6d96be2008-07-09 11:05:10 +00002745 else \
thsf01be152008-09-18 11:57:27 +00002746 CLEAR_FP_COND(cc, env->active_fpu); \
thsb6d96be2008-07-09 11:05:10 +00002747} \
aurel32c01fccd2009-03-08 00:06:01 +00002748void helper_cmpabs_d_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \
thsb6d96be2008-07-09 11:05:10 +00002749{ \
2750 int c; \
2751 fdt0 = float64_abs(fdt0); \
2752 fdt1 = float64_abs(fdt1); \
2753 c = cond; \
2754 update_fcr31(); \
2755 if (c) \
thsf01be152008-09-18 11:57:27 +00002756 SET_FP_COND(cc, env->active_fpu); \
thsb6d96be2008-07-09 11:05:10 +00002757 else \
thsf01be152008-09-18 11:57:27 +00002758 CLEAR_FP_COND(cc, env->active_fpu); \
thsfd4a04e2007-05-18 11:55:54 +00002759}
2760
aurel32cd5158e2008-12-07 23:26:24 +00002761static int float64_is_unordered(int sig, float64 a, float64 b STATUS_PARAM)
thsfd4a04e2007-05-18 11:55:54 +00002762{
2763 if (float64_is_signaling_nan(a) ||
2764 float64_is_signaling_nan(b) ||
2765 (sig && (float64_is_nan(a) || float64_is_nan(b)))) {
2766 float_raise(float_flag_invalid, status);
2767 return 1;
2768 } else if (float64_is_nan(a) || float64_is_nan(b)) {
2769 return 1;
2770 } else {
2771 return 0;
2772 }
2773}
2774
2775/* NOTE: the comma operator will make "cond" to eval to false,
2776 * but float*_is_unordered() is still called. */
thsf01be152008-09-18 11:57:27 +00002777FOP_COND_D(f, (float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status), 0))
2778FOP_COND_D(un, float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status))
2779FOP_COND_D(eq, !float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status) && float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
2780FOP_COND_D(ueq, float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status) || float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
2781FOP_COND_D(olt, !float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status) && float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
2782FOP_COND_D(ult, float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status) || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
2783FOP_COND_D(ole, !float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status) && float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
2784FOP_COND_D(ule, float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status) || float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
thsfd4a04e2007-05-18 11:55:54 +00002785/* NOTE: the comma operator will make "cond" to eval to false,
2786 * but float*_is_unordered() is still called. */
thsf01be152008-09-18 11:57:27 +00002787FOP_COND_D(sf, (float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status), 0))
2788FOP_COND_D(ngle,float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status))
2789FOP_COND_D(seq, !float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status) && float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
2790FOP_COND_D(ngl, float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status) || float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
2791FOP_COND_D(lt, !float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status) && float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
2792FOP_COND_D(nge, float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status) || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
2793FOP_COND_D(le, !float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status) && float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
2794FOP_COND_D(ngt, float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status) || float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
thsfd4a04e2007-05-18 11:55:54 +00002795
thsb6d96be2008-07-09 11:05:10 +00002796#define FOP_COND_S(op, cond) \
aurel32c01fccd2009-03-08 00:06:01 +00002797void helper_cmp_s_ ## op (uint32_t fst0, uint32_t fst1, int cc) \
thsb6d96be2008-07-09 11:05:10 +00002798{ \
2799 int c = cond; \
2800 update_fcr31(); \
2801 if (c) \
thsf01be152008-09-18 11:57:27 +00002802 SET_FP_COND(cc, env->active_fpu); \
thsb6d96be2008-07-09 11:05:10 +00002803 else \
thsf01be152008-09-18 11:57:27 +00002804 CLEAR_FP_COND(cc, env->active_fpu); \
thsb6d96be2008-07-09 11:05:10 +00002805} \
aurel32c01fccd2009-03-08 00:06:01 +00002806void helper_cmpabs_s_ ## op (uint32_t fst0, uint32_t fst1, int cc) \
thsb6d96be2008-07-09 11:05:10 +00002807{ \
2808 int c; \
2809 fst0 = float32_abs(fst0); \
2810 fst1 = float32_abs(fst1); \
2811 c = cond; \
2812 update_fcr31(); \
2813 if (c) \
thsf01be152008-09-18 11:57:27 +00002814 SET_FP_COND(cc, env->active_fpu); \
thsb6d96be2008-07-09 11:05:10 +00002815 else \
thsf01be152008-09-18 11:57:27 +00002816 CLEAR_FP_COND(cc, env->active_fpu); \
thsfd4a04e2007-05-18 11:55:54 +00002817}
2818
aurel32cd5158e2008-12-07 23:26:24 +00002819static flag float32_is_unordered(int sig, float32 a, float32 b STATUS_PARAM)
thsfd4a04e2007-05-18 11:55:54 +00002820{
thsfd4a04e2007-05-18 11:55:54 +00002821 if (float32_is_signaling_nan(a) ||
2822 float32_is_signaling_nan(b) ||
2823 (sig && (float32_is_nan(a) || float32_is_nan(b)))) {
2824 float_raise(float_flag_invalid, status);
2825 return 1;
2826 } else if (float32_is_nan(a) || float32_is_nan(b)) {
2827 return 1;
2828 } else {
2829 return 0;
2830 }
2831}
2832
2833/* NOTE: the comma operator will make "cond" to eval to false,
2834 * but float*_is_unordered() is still called. */
thsf01be152008-09-18 11:57:27 +00002835FOP_COND_S(f, (float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status), 0))
2836FOP_COND_S(un, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status))
2837FOP_COND_S(eq, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) && float32_eq(fst0, fst1, &env->active_fpu.fp_status))
2838FOP_COND_S(ueq, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) || float32_eq(fst0, fst1, &env->active_fpu.fp_status))
2839FOP_COND_S(olt, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) && float32_lt(fst0, fst1, &env->active_fpu.fp_status))
2840FOP_COND_S(ult, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) || float32_lt(fst0, fst1, &env->active_fpu.fp_status))
2841FOP_COND_S(ole, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) && float32_le(fst0, fst1, &env->active_fpu.fp_status))
2842FOP_COND_S(ule, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) || float32_le(fst0, fst1, &env->active_fpu.fp_status))
thsfd4a04e2007-05-18 11:55:54 +00002843/* NOTE: the comma operator will make "cond" to eval to false,
2844 * but float*_is_unordered() is still called. */
thsf01be152008-09-18 11:57:27 +00002845FOP_COND_S(sf, (float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status), 0))
2846FOP_COND_S(ngle,float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status))
2847FOP_COND_S(seq, !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) && float32_eq(fst0, fst1, &env->active_fpu.fp_status))
2848FOP_COND_S(ngl, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) || float32_eq(fst0, fst1, &env->active_fpu.fp_status))
2849FOP_COND_S(lt, !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) && float32_lt(fst0, fst1, &env->active_fpu.fp_status))
2850FOP_COND_S(nge, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) || float32_lt(fst0, fst1, &env->active_fpu.fp_status))
2851FOP_COND_S(le, !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) && float32_le(fst0, fst1, &env->active_fpu.fp_status))
2852FOP_COND_S(ngt, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) || float32_le(fst0, fst1, &env->active_fpu.fp_status))
thsfd4a04e2007-05-18 11:55:54 +00002853
thsb6d96be2008-07-09 11:05:10 +00002854#define FOP_COND_PS(op, condl, condh) \
aurel32c01fccd2009-03-08 00:06:01 +00002855void helper_cmp_ps_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \
thsb6d96be2008-07-09 11:05:10 +00002856{ \
2857 uint32_t fst0 = float32_abs(fdt0 & 0XFFFFFFFF); \
2858 uint32_t fsth0 = float32_abs(fdt0 >> 32); \
2859 uint32_t fst1 = float32_abs(fdt1 & 0XFFFFFFFF); \
2860 uint32_t fsth1 = float32_abs(fdt1 >> 32); \
2861 int cl = condl; \
2862 int ch = condh; \
2863 \
2864 update_fcr31(); \
2865 if (cl) \
thsf01be152008-09-18 11:57:27 +00002866 SET_FP_COND(cc, env->active_fpu); \
thsb6d96be2008-07-09 11:05:10 +00002867 else \
thsf01be152008-09-18 11:57:27 +00002868 CLEAR_FP_COND(cc, env->active_fpu); \
thsb6d96be2008-07-09 11:05:10 +00002869 if (ch) \
thsf01be152008-09-18 11:57:27 +00002870 SET_FP_COND(cc + 1, env->active_fpu); \
thsb6d96be2008-07-09 11:05:10 +00002871 else \
thsf01be152008-09-18 11:57:27 +00002872 CLEAR_FP_COND(cc + 1, env->active_fpu); \
thsb6d96be2008-07-09 11:05:10 +00002873} \
aurel32c01fccd2009-03-08 00:06:01 +00002874void helper_cmpabs_ps_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \
thsb6d96be2008-07-09 11:05:10 +00002875{ \
2876 uint32_t fst0 = float32_abs(fdt0 & 0XFFFFFFFF); \
2877 uint32_t fsth0 = float32_abs(fdt0 >> 32); \
2878 uint32_t fst1 = float32_abs(fdt1 & 0XFFFFFFFF); \
2879 uint32_t fsth1 = float32_abs(fdt1 >> 32); \
2880 int cl = condl; \
2881 int ch = condh; \
2882 \
2883 update_fcr31(); \
2884 if (cl) \
thsf01be152008-09-18 11:57:27 +00002885 SET_FP_COND(cc, env->active_fpu); \
thsb6d96be2008-07-09 11:05:10 +00002886 else \
thsf01be152008-09-18 11:57:27 +00002887 CLEAR_FP_COND(cc, env->active_fpu); \
thsb6d96be2008-07-09 11:05:10 +00002888 if (ch) \
thsf01be152008-09-18 11:57:27 +00002889 SET_FP_COND(cc + 1, env->active_fpu); \
thsb6d96be2008-07-09 11:05:10 +00002890 else \
thsf01be152008-09-18 11:57:27 +00002891 CLEAR_FP_COND(cc + 1, env->active_fpu); \
thsfd4a04e2007-05-18 11:55:54 +00002892}
2893
2894/* NOTE: the comma operator will make "cond" to eval to false,
2895 * but float*_is_unordered() is still called. */
thsf01be152008-09-18 11:57:27 +00002896FOP_COND_PS(f, (float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status), 0),
2897 (float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status), 0))
2898FOP_COND_PS(un, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status),
2899 float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status))
2900FOP_COND_PS(eq, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) && float32_eq(fst0, fst1, &env->active_fpu.fp_status),
2901 !float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status) && float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
2902FOP_COND_PS(ueq, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) || float32_eq(fst0, fst1, &env->active_fpu.fp_status),
2903 float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status) || float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
2904FOP_COND_PS(olt, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) && float32_lt(fst0, fst1, &env->active_fpu.fp_status),
2905 !float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status) && float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
2906FOP_COND_PS(ult, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) || float32_lt(fst0, fst1, &env->active_fpu.fp_status),
2907 float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status) || float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
2908FOP_COND_PS(ole, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) && float32_le(fst0, fst1, &env->active_fpu.fp_status),
2909 !float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status) && float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
2910FOP_COND_PS(ule, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) || float32_le(fst0, fst1, &env->active_fpu.fp_status),
2911 float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status) || float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
thsfd4a04e2007-05-18 11:55:54 +00002912/* NOTE: the comma operator will make "cond" to eval to false,
2913 * but float*_is_unordered() is still called. */
thsf01be152008-09-18 11:57:27 +00002914FOP_COND_PS(sf, (float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status), 0),
2915 (float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status), 0))
2916FOP_COND_PS(ngle,float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status),
2917 float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status))
2918FOP_COND_PS(seq, !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) && float32_eq(fst0, fst1, &env->active_fpu.fp_status),
2919 !float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status) && float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
2920FOP_COND_PS(ngl, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) || float32_eq(fst0, fst1, &env->active_fpu.fp_status),
2921 float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status) || float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
2922FOP_COND_PS(lt, !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) && float32_lt(fst0, fst1, &env->active_fpu.fp_status),
2923 !float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status) && float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
2924FOP_COND_PS(nge, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) || float32_lt(fst0, fst1, &env->active_fpu.fp_status),
2925 float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status) || float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
2926FOP_COND_PS(le, !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) && float32_le(fst0, fst1, &env->active_fpu.fp_status),
2927 !float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status) && float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
2928FOP_COND_PS(ngt, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) || float32_le(fst0, fst1, &env->active_fpu.fp_status),
2929 float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status) || float32_le(fsth0, fsth1, &env->active_fpu.fp_status))