blob: 9f8adfd39f79535242c09474cf7a5b408a27ad94 [file] [log] [blame]
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001/*
2 * MIPS emulation helpers for qemu.
3 *
4 * Copyright (c) 2004-2005 Jocelyn Mayer
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 */
19#include <stdlib.h>
David 'Digit' Turnera889d352014-03-20 12:35:32 +010020#include "cpu.h"
David 'Digit' Turnere90d6652013-12-14 14:55:12 +010021#include "qemu/host-utils.h"
David 'Digit' Turner86b1fb02014-03-21 15:20:21 +010022#include "tcg.h"
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -080023#include "helper.h"
David 'Digit' Turnera889d352014-03-20 12:35:32 +010024
25#if !defined(CONFIG_USER_ONLY)
26#include "exec/softmmu_exec.h"
27#endif /* !defined(CONFIG_USER_ONLY) */
28
29#ifndef CONFIG_USER_ONLY
30static inline void cpu_mips_tlb_flush (CPUMIPSState *env, int flush_global);
31#endif
32
33static inline void compute_hflags(CPUMIPSState *env)
34{
35 env->hflags &= ~(MIPS_HFLAG_COP1X | MIPS_HFLAG_64 | MIPS_HFLAG_CP0 |
36 MIPS_HFLAG_F64 | MIPS_HFLAG_FPU | MIPS_HFLAG_KSU |
37 MIPS_HFLAG_UX);
38 if (!(env->CP0_Status & (1 << CP0St_EXL)) &&
39 !(env->CP0_Status & (1 << CP0St_ERL)) &&
40 !(env->hflags & MIPS_HFLAG_DM)) {
41 env->hflags |= (env->CP0_Status >> CP0St_KSU) & MIPS_HFLAG_KSU;
42 }
43#if defined(TARGET_MIPS64)
44 if (((env->hflags & MIPS_HFLAG_KSU) != MIPS_HFLAG_UM) ||
45 (env->CP0_Status & (1 << CP0St_PX)) ||
46 (env->CP0_Status & (1 << CP0St_UX))) {
47 env->hflags |= MIPS_HFLAG_64;
48 }
49 if (env->CP0_Status & (1 << CP0St_UX)) {
50 env->hflags |= MIPS_HFLAG_UX;
51 }
52#endif
53 if ((env->CP0_Status & (1 << CP0St_CU0)) ||
54 !(env->hflags & MIPS_HFLAG_KSU)) {
55 env->hflags |= MIPS_HFLAG_CP0;
56 }
57 if (env->CP0_Status & (1 << CP0St_CU1)) {
58 env->hflags |= MIPS_HFLAG_FPU;
59 }
60 if (env->CP0_Status & (1 << CP0St_FR)) {
61 env->hflags |= MIPS_HFLAG_F64;
62 }
63 if (env->insn_flags & ISA_MIPS32R2) {
64 if (env->active_fpu.fcr0 & (1 << FCR0_F64)) {
65 env->hflags |= MIPS_HFLAG_COP1X;
66 }
67 } else if (env->insn_flags & ISA_MIPS32) {
68 if (env->hflags & MIPS_HFLAG_64) {
69 env->hflags |= MIPS_HFLAG_COP1X;
70 }
71 } else if (env->insn_flags & ISA_MIPS4) {
72 /* All supported MIPS IV CPUs use the XX (CU3) to enable
73 and disable the MIPS IV extensions to the MIPS III ISA.
74 Some other MIPS IV CPUs ignore the bit, so the check here
75 would be too restrictive for them. */
76 if (env->CP0_Status & (1 << CP0St_CU3)) {
77 env->hflags |= MIPS_HFLAG_COP1X;
78 }
79 }
80}
81
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -080082/*****************************************************************************/
83/* Exceptions processing helpers */
84
David 'Digit' Turner6480c962014-04-03 12:38:04 +020085void helper_raise_exception_err (CPUMIPSState *env,
86 uint32_t exception, int error_code)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -080087{
88#if 1
89 if (exception < 0x100)
90 qemu_log("%s: %d %d\n", __func__, exception, error_code);
91#endif
92 env->exception_index = exception;
93 env->error_code = error_code;
David 'Digit' Turner85c62202014-02-16 20:53:40 +010094 cpu_loop_exit(env);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -080095}
96
David 'Digit' Turner6480c962014-04-03 12:38:04 +020097void helper_raise_exception (CPUMIPSState *env, uint32_t exception)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -080098{
David 'Digit' Turner6480c962014-04-03 12:38:04 +020099 helper_raise_exception_err(env, exception, 0);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800100}
101
David 'Digit' Turner6480c962014-04-03 12:38:04 +0200102void helper_interrupt_restart (CPUMIPSState *env)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800103{
104 if (!(env->CP0_Status & (1 << CP0St_EXL)) &&
105 !(env->CP0_Status & (1 << CP0St_ERL)) &&
106 !(env->hflags & MIPS_HFLAG_DM) &&
107 (env->CP0_Status & (1 << CP0St_IE)) &&
108 (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask)) {
109 env->CP0_Cause &= ~(0x1f << CP0Ca_EC);
David 'Digit' Turner6480c962014-04-03 12:38:04 +0200110 helper_raise_exception(env, EXCP_EXT_INTERRUPT);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800111 }
112}
113
114#if !defined(CONFIG_USER_ONLY)
David 'Digit' Turner6480c962014-04-03 12:38:04 +0200115static void do_restore_state (CPUMIPSState *env, uintptr_t pc)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800116{
117 TranslationBlock *tb;
David 'Digit' Turnerc0052462014-02-25 18:39:29 +0100118
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800119 tb = tb_find_pc (pc);
120 if (tb) {
David 'Digit' Turner3e0677d2014-03-07 15:01:06 +0100121 cpu_restore_state (env, pc);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800122 }
123}
124#endif
125
126#if defined(CONFIG_USER_ONLY)
127#define HELPER_LD(name, insn, type) \
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200128static inline type do_##name(CPUMIPSState *env, target_ulong addr, \
129 int mem_idx) \
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800130{ \
David 'Digit' Turnereca7bc22014-03-14 23:58:39 +0100131 return (type) cpu_##insn##_raw(env, addr); \
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800132}
133#else
134#define HELPER_LD(name, insn, type) \
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200135static inline type do_##name(CPUMIPSState *env, target_ulong addr, \
136 int mem_idx) \
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800137{ \
138 switch (mem_idx) \
139 { \
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200140 case 0: return (type) cpu_##insn##_kernel(env, addr); break; \
141 case 1: return (type) cpu_##insn##_super(env, addr); break; \
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800142 default: \
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200143 case 2: return (type) cpu_##insn##_user(env, addr); break; \
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800144 } \
145}
146#endif
147HELPER_LD(lbu, ldub, uint8_t)
148HELPER_LD(lw, ldl, int32_t)
149#ifdef TARGET_MIPS64
150HELPER_LD(ld, ldq, int64_t)
151#endif
152#undef HELPER_LD
153
154#if defined(CONFIG_USER_ONLY)
155#define HELPER_ST(name, insn, type) \
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200156static inline void do_##name(CPUMIPSState *env, target_ulong addr, \
157 type val, int mem_idx) \
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800158{ \
David 'Digit' Turnereca7bc22014-03-14 23:58:39 +0100159 cpu_##insn##_raw(env, addr, val); \
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800160}
161#else
162#define HELPER_ST(name, insn, type) \
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200163static inline void do_##name(CPUMIPSState *env, target_ulong addr, \
164 type val, int mem_idx) \
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800165{ \
166 switch (mem_idx) \
167 { \
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200168 case 0: cpu_##insn##_kernel(env, addr, val); break; \
169 case 1: cpu_##insn##_super(env, addr, val); break; \
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800170 default: \
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200171 case 2: cpu_##insn##_user(env, addr, val); break; \
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800172 } \
173}
174#endif
175HELPER_ST(sb, stb, uint8_t)
176HELPER_ST(sw, stl, uint32_t)
177#ifdef TARGET_MIPS64
178HELPER_ST(sd, stq, uint64_t)
179#endif
180#undef HELPER_ST
181
182target_ulong helper_clo (target_ulong arg1)
183{
184 return clo32(arg1);
185}
186
187target_ulong helper_clz (target_ulong arg1)
188{
189 return clz32(arg1);
190}
191
192#if defined(TARGET_MIPS64)
193target_ulong helper_dclo (target_ulong arg1)
194{
195 return clo64(arg1);
196}
197
198target_ulong helper_dclz (target_ulong arg1)
199{
200 return clz64(arg1);
201}
202#endif /* TARGET_MIPS64 */
203
204/* 64 bits arithmetic for 32 bits hosts */
David 'Digit' Turner5c5a6e12014-04-03 15:48:19 +0200205static inline uint64_t get_HILO(CPUMIPSState *env)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800206{
207 return ((uint64_t)(env->active_tc.HI[0]) << 32) | (uint32_t)env->active_tc.LO[0];
208}
209
David 'Digit' Turner5c5a6e12014-04-03 15:48:19 +0200210static inline void set_HILO (CPUMIPSState *env, uint64_t HILO)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800211{
212 env->active_tc.LO[0] = (int32_t)HILO;
213 env->active_tc.HI[0] = (int32_t)(HILO >> 32);
214}
215
David 'Digit' Turner5c5a6e12014-04-03 15:48:19 +0200216static inline void set_HIT0_LO (CPUMIPSState *env, target_ulong arg1, uint64_t HILO)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800217{
218 env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF);
219 arg1 = env->active_tc.HI[0] = (int32_t)(HILO >> 32);
220}
221
David 'Digit' Turner5c5a6e12014-04-03 15:48:19 +0200222static inline void set_HI_LOT0 (CPUMIPSState *env, target_ulong arg1, uint64_t HILO)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800223{
224 arg1 = env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF);
225 env->active_tc.HI[0] = (int32_t)(HILO >> 32);
226}
227
228/* Multiplication variants of the vr54xx. */
David 'Digit' Turner5c5a6e12014-04-03 15:48:19 +0200229target_ulong helper_muls(CPUMIPSState *env, target_ulong arg1,
230 target_ulong arg2)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800231{
David 'Digit' Turner5c5a6e12014-04-03 15:48:19 +0200232 set_HI_LOT0(env, arg1, 0 - ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800233
234 return arg1;
235}
236
David 'Digit' Turner5c5a6e12014-04-03 15:48:19 +0200237target_ulong helper_mulsu(CPUMIPSState *env, target_ulong arg1,
238 target_ulong arg2)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800239{
David 'Digit' Turner5c5a6e12014-04-03 15:48:19 +0200240 set_HI_LOT0(env, arg1, 0 - ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800241
242 return arg1;
243}
244
David 'Digit' Turner5c5a6e12014-04-03 15:48:19 +0200245target_ulong helper_macc(CPUMIPSState *env, target_ulong arg1,
246 target_ulong arg2)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800247{
David 'Digit' Turner5c5a6e12014-04-03 15:48:19 +0200248 set_HI_LOT0(env, arg1, ((int64_t)get_HILO(env)) + ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800249
250 return arg1;
251}
252
David 'Digit' Turner5c5a6e12014-04-03 15:48:19 +0200253target_ulong helper_macchi(CPUMIPSState *env, target_ulong arg1,
254 target_ulong arg2)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800255{
David 'Digit' Turner5c5a6e12014-04-03 15:48:19 +0200256 set_HIT0_LO(env, arg1, ((int64_t)get_HILO(env)) + ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800257
258 return arg1;
259}
260
David 'Digit' Turner5c5a6e12014-04-03 15:48:19 +0200261target_ulong helper_maccu(CPUMIPSState *env, target_ulong arg1,
262 target_ulong arg2)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800263{
David 'Digit' Turner5c5a6e12014-04-03 15:48:19 +0200264 set_HI_LOT0(env, arg1, ((uint64_t)get_HILO(env)) + ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800265
266 return arg1;
267}
268
David 'Digit' Turner5c5a6e12014-04-03 15:48:19 +0200269target_ulong helper_macchiu(CPUMIPSState *env, target_ulong arg1,
270 target_ulong arg2)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800271{
David 'Digit' Turner5c5a6e12014-04-03 15:48:19 +0200272 set_HIT0_LO(env, arg1, ((uint64_t)get_HILO(env)) + ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800273
274 return arg1;
275}
276
David 'Digit' Turner5c5a6e12014-04-03 15:48:19 +0200277target_ulong helper_msac(CPUMIPSState *env, target_ulong arg1,
278 target_ulong arg2)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800279{
David 'Digit' Turner5c5a6e12014-04-03 15:48:19 +0200280 set_HI_LOT0(env, arg1, ((int64_t)get_HILO(env)) - ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800281
282 return arg1;
283}
284
David 'Digit' Turner5c5a6e12014-04-03 15:48:19 +0200285target_ulong helper_msachi(CPUMIPSState *env, target_ulong arg1,
286 target_ulong arg2)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800287{
David 'Digit' Turner5c5a6e12014-04-03 15:48:19 +0200288 set_HIT0_LO(env, arg1, ((int64_t)get_HILO(env)) - ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800289
290 return arg1;
291}
292
David 'Digit' Turner5c5a6e12014-04-03 15:48:19 +0200293target_ulong helper_msacu(CPUMIPSState *env, target_ulong arg1,
294 target_ulong arg2)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800295{
David 'Digit' Turner5c5a6e12014-04-03 15:48:19 +0200296 set_HI_LOT0(env, arg1, ((uint64_t)get_HILO(env)) - ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800297
298 return arg1;
299}
300
David 'Digit' Turner5c5a6e12014-04-03 15:48:19 +0200301target_ulong helper_msachiu(CPUMIPSState *env, target_ulong arg1,
302 target_ulong arg2)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800303{
David 'Digit' Turner5c5a6e12014-04-03 15:48:19 +0200304 set_HIT0_LO(env, arg1, ((uint64_t)get_HILO(env)) - ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800305
306 return arg1;
307}
308
David 'Digit' Turner5c5a6e12014-04-03 15:48:19 +0200309target_ulong helper_mulhi(CPUMIPSState *env, target_ulong arg1,
310 target_ulong arg2)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800311{
David 'Digit' Turner5c5a6e12014-04-03 15:48:19 +0200312 set_HIT0_LO(env, arg1, (int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800313
314 return arg1;
315}
316
David 'Digit' Turner5c5a6e12014-04-03 15:48:19 +0200317target_ulong helper_mulhiu(CPUMIPSState *env, target_ulong arg1,
318 target_ulong arg2)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800319{
David 'Digit' Turner5c5a6e12014-04-03 15:48:19 +0200320 set_HIT0_LO(env, arg1, (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800321
322 return arg1;
323}
324
David 'Digit' Turner5c5a6e12014-04-03 15:48:19 +0200325target_ulong helper_mulshi(CPUMIPSState *env, target_ulong arg1,
326 target_ulong arg2)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800327{
David 'Digit' Turner5c5a6e12014-04-03 15:48:19 +0200328 set_HIT0_LO(env, arg1, 0 - ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800329
330 return arg1;
331}
332
David 'Digit' Turner5c5a6e12014-04-03 15:48:19 +0200333target_ulong helper_mulshiu(CPUMIPSState *env, target_ulong arg1,
334 target_ulong arg2)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800335{
David 'Digit' Turner5c5a6e12014-04-03 15:48:19 +0200336 set_HIT0_LO(env, arg1, 0 - ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800337
338 return arg1;
339}
340
341#ifdef TARGET_MIPS64
David 'Digit' Turner5c5a6e12014-04-03 15:48:19 +0200342void helper_dmult (CPUMIPSState *env, target_ulong arg1, target_ulong arg2)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800343{
344 muls64(&(env->active_tc.LO[0]), &(env->active_tc.HI[0]), arg1, arg2);
345}
346
David 'Digit' Turner5c5a6e12014-04-03 15:48:19 +0200347void helper_dmultu (CPUMIPSState *env, target_ulong arg1, target_ulong arg2)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800348{
349 mulu64(&(env->active_tc.LO[0]), &(env->active_tc.HI[0]), arg1, arg2);
350}
351#endif
352
353#ifndef CONFIG_USER_ONLY
354
David 'Digit' Turner6cca40e2014-04-03 17:25:42 +0200355static inline hwaddr do_translate_address(CPUMIPSState *env,
356 target_ulong address,
357 int rw)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800358{
David 'Digit' Turnerbcde1092014-01-09 23:19:19 +0100359 hwaddr lladdr;
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800360
David 'Digit' Turner6cca40e2014-04-03 17:25:42 +0200361 lladdr = cpu_mips_translate_address(env, address, rw);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800362
Chris Dearmanfa32c322014-02-25 19:49:16 -0800363 if (lladdr == (hwaddr)-1LL) {
David 'Digit' Turner6cca40e2014-04-03 17:25:42 +0200364 cpu_loop_exit(env);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800365 } else {
366 return lladdr;
367 }
368}
369
370#define HELPER_LD_ATOMIC(name, insn) \
David 'Digit' Turner6cca40e2014-04-03 17:25:42 +0200371target_ulong helper_##name(CPUMIPSState *env, target_ulong arg, int mem_idx) \
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800372{ \
David 'Digit' Turner6cca40e2014-04-03 17:25:42 +0200373 env->lladdr = do_translate_address(env, arg, 0); \
David 'Digit' Turnercd35ed22014-04-03 17:23:12 +0200374 /* NOTE(digit): Use of 'cpu_single_env' works around compiler bug! */ \
David 'Digit' Turner6cca40e2014-04-03 17:25:42 +0200375 cpu_single_env->llval = do_##insn(env, arg, mem_idx); \
376 return env->llval; \
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800377}
378HELPER_LD_ATOMIC(ll, lw)
379#ifdef TARGET_MIPS64
380HELPER_LD_ATOMIC(lld, ld)
381#endif
382#undef HELPER_LD_ATOMIC
383
384#define HELPER_ST_ATOMIC(name, ld_insn, st_insn, almask) \
David 'Digit' Turner6cca40e2014-04-03 17:25:42 +0200385target_ulong helper_##name(CPUMIPSState *env, target_ulong arg1, \
David 'Digit' Turnercd35ed22014-04-03 17:23:12 +0200386 target_ulong arg2, int mem_idx) \
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800387{ \
388 target_long tmp; \
389 \
390 if (arg2 & almask) { \
391 env->CP0_BadVAddr = arg2; \
David 'Digit' Turner6cca40e2014-04-03 17:25:42 +0200392 helper_raise_exception(env, EXCP_AdES); \
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800393 } \
David 'Digit' Turner6cca40e2014-04-03 17:25:42 +0200394 if (do_translate_address(env, arg2, 1) == env->lladdr) { \
395 tmp = do_##ld_insn(env, arg2, mem_idx); \
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800396 if (tmp == env->llval) { \
David 'Digit' Turner6cca40e2014-04-03 17:25:42 +0200397 do_##st_insn(env, arg2, arg1, mem_idx); \
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800398 return 1; \
399 } \
400 } \
401 return 0; \
402}
403HELPER_ST_ATOMIC(sc, lw, sw, 0x3)
404#ifdef TARGET_MIPS64
405HELPER_ST_ATOMIC(scd, ld, sd, 0x7)
406#endif
407#undef HELPER_ST_ATOMIC
408#endif
409
410#ifdef TARGET_WORDS_BIGENDIAN
411#define GET_LMASK(v) ((v) & 3)
412#define GET_OFFSET(addr, offset) (addr + (offset))
413#else
414#define GET_LMASK(v) (((v) & 3) ^ 3)
415#define GET_OFFSET(addr, offset) (addr - (offset))
416#endif
417
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200418target_ulong helper_lwl(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
419 int mem_idx)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800420{
421 target_ulong tmp;
422
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200423 tmp = do_lbu(env, arg2, mem_idx);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800424 arg1 = (arg1 & 0x00FFFFFF) | (tmp << 24);
425
426 if (GET_LMASK(arg2) <= 2) {
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200427 tmp = do_lbu(env, GET_OFFSET(arg2, 1), mem_idx);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800428 arg1 = (arg1 & 0xFF00FFFF) | (tmp << 16);
429 }
430
431 if (GET_LMASK(arg2) <= 1) {
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200432 tmp = do_lbu(env, GET_OFFSET(arg2, 2), mem_idx);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800433 arg1 = (arg1 & 0xFFFF00FF) | (tmp << 8);
434 }
435
436 if (GET_LMASK(arg2) == 0) {
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200437 tmp = do_lbu(env, GET_OFFSET(arg2, 3), mem_idx);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800438 arg1 = (arg1 & 0xFFFFFF00) | tmp;
439 }
440 return (int32_t)arg1;
441}
442
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200443target_ulong helper_lwr(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
444 int mem_idx)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800445{
446 target_ulong tmp;
447
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200448 tmp = do_lbu(env, arg2, mem_idx);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800449 arg1 = (arg1 & 0xFFFFFF00) | tmp;
450
451 if (GET_LMASK(arg2) >= 1) {
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200452 tmp = do_lbu(env, GET_OFFSET(arg2, -1), mem_idx);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800453 arg1 = (arg1 & 0xFFFF00FF) | (tmp << 8);
454 }
455
456 if (GET_LMASK(arg2) >= 2) {
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200457 tmp = do_lbu(env, GET_OFFSET(arg2, -2), mem_idx);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800458 arg1 = (arg1 & 0xFF00FFFF) | (tmp << 16);
459 }
460
461 if (GET_LMASK(arg2) == 3) {
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200462 tmp = do_lbu(env, GET_OFFSET(arg2, -3), mem_idx);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800463 arg1 = (arg1 & 0x00FFFFFF) | (tmp << 24);
464 }
465 return (int32_t)arg1;
466}
467
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200468void helper_swl(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
469 int mem_idx)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800470{
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200471 do_sb(env, arg2, (uint8_t)(arg1 >> 24), mem_idx);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800472
473 if (GET_LMASK(arg2) <= 2)
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200474 do_sb(env, GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 16), mem_idx);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800475
476 if (GET_LMASK(arg2) <= 1)
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200477 do_sb(env, GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 8), mem_idx);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800478
479 if (GET_LMASK(arg2) == 0)
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200480 do_sb(env, GET_OFFSET(arg2, 3), (uint8_t)arg1, mem_idx);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800481}
482
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200483void helper_swr(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
484 int mem_idx)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800485{
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200486 do_sb(env, arg2, (uint8_t)arg1, mem_idx);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800487
488 if (GET_LMASK(arg2) >= 1)
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200489 do_sb(env, GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8), mem_idx);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800490
491 if (GET_LMASK(arg2) >= 2)
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200492 do_sb(env, GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16), mem_idx);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800493
494 if (GET_LMASK(arg2) == 3)
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200495 do_sb(env, GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24), mem_idx);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800496}
497
498#if defined(TARGET_MIPS64)
499/* "half" load and stores. We must do the memory access inline,
500 or fault handling won't work. */
501
502#ifdef TARGET_WORDS_BIGENDIAN
503#define GET_LMASK64(v) ((v) & 7)
504#else
505#define GET_LMASK64(v) (((v) & 7) ^ 7)
506#endif
507
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200508target_ulong helper_ldl(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
509 int mem_idx)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800510{
511 uint64_t tmp;
512
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200513 tmp = do_lbu(env, arg2, mem_idx);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800514 arg1 = (arg1 & 0x00FFFFFFFFFFFFFFULL) | (tmp << 56);
515
516 if (GET_LMASK64(arg2) <= 6) {
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200517 tmp = do_lbu(env, GET_OFFSET(arg2, 1), mem_idx);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800518 arg1 = (arg1 & 0xFF00FFFFFFFFFFFFULL) | (tmp << 48);
519 }
520
521 if (GET_LMASK64(arg2) <= 5) {
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200522 tmp = do_lbu(env, GET_OFFSET(arg2, 2), mem_idx);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800523 arg1 = (arg1 & 0xFFFF00FFFFFFFFFFULL) | (tmp << 40);
524 }
525
526 if (GET_LMASK64(arg2) <= 4) {
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200527 tmp = do_lbu(env, GET_OFFSET(arg2, 3), mem_idx);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800528 arg1 = (arg1 & 0xFFFFFF00FFFFFFFFULL) | (tmp << 32);
529 }
530
531 if (GET_LMASK64(arg2) <= 3) {
532 tmp = do_lbu(GET_OFFSET(arg2, 4), mem_idx);
533 arg1 = (arg1 & 0xFFFFFFFF00FFFFFFULL) | (tmp << 24);
534 }
535
536 if (GET_LMASK64(arg2) <= 2) {
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200537 tmp = do_lbu(env, GET_OFFSET(arg2, 5), mem_idx);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800538 arg1 = (arg1 & 0xFFFFFFFFFF00FFFFULL) | (tmp << 16);
539 }
540
541 if (GET_LMASK64(arg2) <= 1) {
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200542 tmp = do_lbu(env, GET_OFFSET(arg2, 6), mem_idx);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800543 arg1 = (arg1 & 0xFFFFFFFFFFFF00FFULL) | (tmp << 8);
544 }
545
546 if (GET_LMASK64(arg2) == 0) {
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200547 tmp = do_lbu(env, GET_OFFSET(arg2, 7), mem_idx);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800548 arg1 = (arg1 & 0xFFFFFFFFFFFFFF00ULL) | tmp;
549 }
550
551 return arg1;
552}
553
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200554target_ulong helper_ldr(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
555 int mem_idx)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800556{
557 uint64_t tmp;
558
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200559 tmp = do_lbu(env, arg2, mem_idx);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800560 arg1 = (arg1 & 0xFFFFFFFFFFFFFF00ULL) | tmp;
561
562 if (GET_LMASK64(arg2) >= 1) {
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200563 tmp = do_lbu(env, GET_OFFSET(arg2, -1), mem_idx);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800564 arg1 = (arg1 & 0xFFFFFFFFFFFF00FFULL) | (tmp << 8);
565 }
566
567 if (GET_LMASK64(arg2) >= 2) {
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200568 tmp = do_lbu(env, GET_OFFSET(arg2, -2), mem_idx);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800569 arg1 = (arg1 & 0xFFFFFFFFFF00FFFFULL) | (tmp << 16);
570 }
571
572 if (GET_LMASK64(arg2) >= 3) {
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200573 tmp = do_lbu(env, GET_OFFSET(arg2, -3), mem_idx);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800574 arg1 = (arg1 & 0xFFFFFFFF00FFFFFFULL) | (tmp << 24);
575 }
576
577 if (GET_LMASK64(arg2) >= 4) {
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200578 tmp = do_lbu(env, GET_OFFSET(arg2, -4), mem_idx);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800579 arg1 = (arg1 & 0xFFFFFF00FFFFFFFFULL) | (tmp << 32);
580 }
581
582 if (GET_LMASK64(arg2) >= 5) {
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200583 tmp = do_lbu(env, GET_OFFSET(arg2, -5), mem_idx);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800584 arg1 = (arg1 & 0xFFFF00FFFFFFFFFFULL) | (tmp << 40);
585 }
586
587 if (GET_LMASK64(arg2) >= 6) {
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200588 tmp = do_lbu(env, GET_OFFSET(arg2, -6), mem_idx);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800589 arg1 = (arg1 & 0xFF00FFFFFFFFFFFFULL) | (tmp << 48);
590 }
591
592 if (GET_LMASK64(arg2) == 7) {
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200593 tmp = do_lbu(env, GET_OFFSET(arg2, -7), mem_idx);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800594 arg1 = (arg1 & 0x00FFFFFFFFFFFFFFULL) | (tmp << 56);
595 }
596
597 return arg1;
598}
599
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200600void helper_sdl(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
601 int mem_idx)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800602{
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200603 do_sb(env, arg2, (uint8_t)(arg1 >> 56), mem_idx);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800604
605 if (GET_LMASK64(arg2) <= 6)
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200606 do_sb(env, GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 48), mem_idx);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800607
608 if (GET_LMASK64(arg2) <= 5)
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200609 do_sb(env, GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 40), mem_idx);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800610
611 if (GET_LMASK64(arg2) <= 4)
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200612 do_sb(env, GET_OFFSET(arg2, 3), (uint8_t)(arg1 >> 32), mem_idx);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800613
614 if (GET_LMASK64(arg2) <= 3)
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200615 do_sb(env, GET_OFFSET(arg2, 4), (uint8_t)(arg1 >> 24), mem_idx);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800616
617 if (GET_LMASK64(arg2) <= 2)
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200618 do_sb(env, GET_OFFSET(arg2, 5), (uint8_t)(arg1 >> 16), mem_idx);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800619
620 if (GET_LMASK64(arg2) <= 1)
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200621 do_sb(env, GET_OFFSET(arg2, 6), (uint8_t)(arg1 >> 8), mem_idx);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800622
623 if (GET_LMASK64(arg2) <= 0)
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200624 do_sb(env, GET_OFFSET(arg2, 7), (uint8_t)arg1, mem_idx);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800625}
626
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200627void helper_sdr(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
628 int mem_idx)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800629{
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200630 do_sb(env, arg2, (uint8_t)arg1, mem_idx);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800631
632 if (GET_LMASK64(arg2) >= 1)
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200633 do_sb(env, GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8), mem_idx);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800634
635 if (GET_LMASK64(arg2) >= 2)
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200636 do_sb(env, GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16), mem_idx);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800637
638 if (GET_LMASK64(arg2) >= 3)
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200639 do_sb(env, GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24), mem_idx);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800640
641 if (GET_LMASK64(arg2) >= 4)
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200642 do_sb(env, GET_OFFSET(arg2, -4), (uint8_t)(arg1 >> 32), mem_idx);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800643
644 if (GET_LMASK64(arg2) >= 5)
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200645 do_sb(env, GET_OFFSET(arg2, -5), (uint8_t)(arg1 >> 40), mem_idx);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800646
647 if (GET_LMASK64(arg2) >= 6)
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200648 do_sb(env, GET_OFFSET(arg2, -6), (uint8_t)(arg1 >> 48), mem_idx);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800649
650 if (GET_LMASK64(arg2) == 7)
David 'Digit' Turnerd62e5382014-04-03 13:13:04 +0200651 do_sb(env, GET_OFFSET(arg2, -7), (uint8_t)(arg1 >> 56), mem_idx);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800652}
653#endif /* TARGET_MIPS64 */
654
655#ifndef CONFIG_USER_ONLY
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +0100656/* tc should point to an int with the value of the global TC index.
657 This function will transform it into a local index within the
658 returned CPUState.
659
660 FIXME: This code assumes that all VPEs have the same number of TCs,
661 which depends on runtime setup. Can probably be fixed by
David 'Digit' Turner06978cc2014-04-03 15:55:43 +0200662 walking the list of CPUMIPSStates. */
663static CPUMIPSState *mips_cpu_map_tc(CPUMIPSState *env, int *tc)
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +0100664{
David 'Digit' Turner66576782014-03-24 16:57:57 +0100665 int vpe_idx, nr_threads = ENV_GET_CPU(env)->nr_threads;
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +0100666 int tc_idx = *tc;
667
668 if (!(env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP))) {
669 /* Not allowed to address other CPUs. */
670 *tc = env->current_tc;
671 return env;
672 }
673
674 vpe_idx = tc_idx / nr_threads;
675 *tc = tc_idx % nr_threads;
David 'Digit' Turnerbf7a22f2014-03-25 16:36:03 +0100676 CPUState *other = qemu_get_cpu(vpe_idx);
677 return other ? other->env_ptr : env;
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +0100678}
679
David 'Digit' Turner811b0292014-03-20 18:08:55 +0100680/* The per VPE CP0_Status register shares some fields with the per TC
681 CP0_TCStatus registers. These fields are wired to the same registers,
682 so changes to either of them should be reflected on both registers.
683
684 Also, EntryHi shares the bottom 8 bit ASID with TCStauts.
685
686 These helper call synchronizes the regs for a given cpu. */
687
688/* Called for updates to CP0_Status. */
David 'Digit' Turner06978cc2014-04-03 15:55:43 +0200689static void sync_c0_status(CPUMIPSState *env, CPUMIPSState *cpu, int tc)
David 'Digit' Turner811b0292014-03-20 18:08:55 +0100690{
691 int32_t tcstatus, *tcst;
692 uint32_t v = cpu->CP0_Status;
693 uint32_t cu, mx, asid, ksu;
694 uint32_t mask = ((1 << CP0TCSt_TCU3)
695 | (1 << CP0TCSt_TCU2)
696 | (1 << CP0TCSt_TCU1)
697 | (1 << CP0TCSt_TCU0)
698 | (1 << CP0TCSt_TMX)
699 | (3 << CP0TCSt_TKSU)
700 | (0xff << CP0TCSt_TASID));
701
702 cu = (v >> CP0St_CU0) & 0xf;
703 mx = (v >> CP0St_MX) & 0x1;
704 ksu = (v >> CP0St_KSU) & 0x3;
705 asid = env->CP0_EntryHi & 0xff;
706
707 tcstatus = cu << CP0TCSt_TCU0;
708 tcstatus |= mx << CP0TCSt_TMX;
709 tcstatus |= ksu << CP0TCSt_TKSU;
710 tcstatus |= asid;
711
712 if (tc == cpu->current_tc) {
713 tcst = &cpu->active_tc.CP0_TCStatus;
714 } else {
715 tcst = &cpu->tcs[tc].CP0_TCStatus;
716 }
717
718 *tcst &= ~mask;
719 *tcst |= tcstatus;
720 compute_hflags(cpu);
721}
722
723/* Called for updates to CP0_TCStatus. */
David 'Digit' Turner06978cc2014-04-03 15:55:43 +0200724static void sync_c0_tcstatus(CPUMIPSState *cpu, int tc,
725 target_ulong v)
David 'Digit' Turner811b0292014-03-20 18:08:55 +0100726{
727 uint32_t status;
728 uint32_t tcu, tmx, tasid, tksu;
729 uint32_t mask = ((1 << CP0St_CU3)
730 | (1 << CP0St_CU2)
731 | (1 << CP0St_CU1)
732 | (1 << CP0St_CU0)
733 | (1 << CP0St_MX)
734 | (3 << CP0St_KSU));
735
736 tcu = (v >> CP0TCSt_TCU0) & 0xf;
737 tmx = (v >> CP0TCSt_TMX) & 0x1;
738 tasid = v & 0xff;
739 tksu = (v >> CP0TCSt_TKSU) & 0x3;
740
741 status = tcu << CP0St_CU0;
742 status |= tmx << CP0St_MX;
743 status |= tksu << CP0St_KSU;
744
745 cpu->CP0_Status &= ~mask;
746 cpu->CP0_Status |= status;
747
748 /* Sync the TASID with EntryHi. */
749 cpu->CP0_EntryHi &= ~0xff;
750 cpu->CP0_EntryHi = tasid;
751
752 compute_hflags(cpu);
753}
754
755/* Called for updates to CP0_EntryHi. */
756static void sync_c0_entryhi(CPUMIPSState *cpu, int tc)
757{
758 int32_t *tcst;
759 uint32_t asid, v = cpu->CP0_EntryHi;
760
761 asid = v & 0xff;
762
763 if (tc == cpu->current_tc) {
764 tcst = &cpu->active_tc.CP0_TCStatus;
765 } else {
766 tcst = &cpu->tcs[tc].CP0_TCStatus;
767 }
768
769 *tcst &= ~0xff;
770 *tcst |= asid;
771}
772
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800773/* CP0 helpers */
David 'Digit' Turner06978cc2014-04-03 15:55:43 +0200774target_ulong helper_mfc0_mvpcontrol(CPUMIPSState *env)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800775{
776 return env->mvp->CP0_MVPControl;
777}
778
David 'Digit' Turner06978cc2014-04-03 15:55:43 +0200779target_ulong helper_mfc0_mvpconf0(CPUMIPSState *env)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800780{
781 return env->mvp->CP0_MVPConf0;
782}
783
David 'Digit' Turner06978cc2014-04-03 15:55:43 +0200784target_ulong helper_mfc0_mvpconf1(CPUMIPSState *env)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800785{
786 return env->mvp->CP0_MVPConf1;
787}
788
David 'Digit' Turner06978cc2014-04-03 15:55:43 +0200789target_ulong helper_mfc0_random(CPUMIPSState *env)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800790{
791 return (int32_t)cpu_mips_get_random(env);
792}
793
David 'Digit' Turner06978cc2014-04-03 15:55:43 +0200794target_ulong helper_mfc0_tcstatus(CPUMIPSState *env)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800795{
796 return env->active_tc.CP0_TCStatus;
797}
798
David 'Digit' Turner06978cc2014-04-03 15:55:43 +0200799target_ulong helper_mftc0_tcstatus(CPUMIPSState *env)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800800{
801 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
David 'Digit' Turner06978cc2014-04-03 15:55:43 +0200802 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800803
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +0100804 if (other_tc == other->current_tc)
805 return other->active_tc.CP0_TCStatus;
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800806 else
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +0100807 return other->tcs[other_tc].CP0_TCStatus;
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800808}
809
David 'Digit' Turner06978cc2014-04-03 15:55:43 +0200810target_ulong helper_mfc0_tcbind(CPUMIPSState *env)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800811{
812 return env->active_tc.CP0_TCBind;
813}
814
David 'Digit' Turner06978cc2014-04-03 15:55:43 +0200815target_ulong helper_mftc0_tcbind(CPUMIPSState *env)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800816{
817 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
David 'Digit' Turner06978cc2014-04-03 15:55:43 +0200818 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800819
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +0100820 if (other_tc == other->current_tc)
821 return other->active_tc.CP0_TCBind;
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800822 else
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +0100823 return other->tcs[other_tc].CP0_TCBind;
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800824}
825
David 'Digit' Turner06978cc2014-04-03 15:55:43 +0200826target_ulong helper_mfc0_tcrestart(CPUMIPSState *env)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800827{
828 return env->active_tc.PC;
829}
830
David 'Digit' Turner06978cc2014-04-03 15:55:43 +0200831target_ulong helper_mftc0_tcrestart(CPUMIPSState *env)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800832{
833 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
David 'Digit' Turner06978cc2014-04-03 15:55:43 +0200834 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800835
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +0100836 if (other_tc == other->current_tc)
837 return other->active_tc.PC;
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800838 else
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +0100839 return other->tcs[other_tc].PC;
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800840}
841
David 'Digit' Turner06978cc2014-04-03 15:55:43 +0200842target_ulong helper_mfc0_tchalt(CPUMIPSState *env)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800843{
844 return env->active_tc.CP0_TCHalt;
845}
846
David 'Digit' Turner06978cc2014-04-03 15:55:43 +0200847target_ulong helper_mftc0_tchalt(CPUMIPSState *env)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800848{
849 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
David 'Digit' Turner06978cc2014-04-03 15:55:43 +0200850 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800851
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +0100852 if (other_tc == other->current_tc)
853 return other->active_tc.CP0_TCHalt;
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800854 else
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +0100855 return other->tcs[other_tc].CP0_TCHalt;
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800856}
857
David 'Digit' Turner06978cc2014-04-03 15:55:43 +0200858target_ulong helper_mfc0_tccontext(CPUMIPSState *env)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800859{
860 return env->active_tc.CP0_TCContext;
861}
862
David 'Digit' Turner06978cc2014-04-03 15:55:43 +0200863target_ulong helper_mftc0_tccontext(CPUMIPSState *env)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800864{
865 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
David 'Digit' Turner06978cc2014-04-03 15:55:43 +0200866 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800867
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +0100868 if (other_tc == other->current_tc)
869 return other->active_tc.CP0_TCContext;
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800870 else
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +0100871 return other->tcs[other_tc].CP0_TCContext;
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800872}
873
David 'Digit' Turner06978cc2014-04-03 15:55:43 +0200874target_ulong helper_mfc0_tcschedule(CPUMIPSState *env)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800875{
876 return env->active_tc.CP0_TCSchedule;
877}
878
David 'Digit' Turner06978cc2014-04-03 15:55:43 +0200879target_ulong helper_mftc0_tcschedule(CPUMIPSState *env)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800880{
881 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
David 'Digit' Turner06978cc2014-04-03 15:55:43 +0200882 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800883
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +0100884 if (other_tc == other->current_tc)
885 return other->active_tc.CP0_TCSchedule;
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800886 else
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +0100887 return other->tcs[other_tc].CP0_TCSchedule;
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800888}
889
David 'Digit' Turner06978cc2014-04-03 15:55:43 +0200890target_ulong helper_mfc0_tcschefback(CPUMIPSState *env)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800891{
892 return env->active_tc.CP0_TCScheFBack;
893}
894
David 'Digit' Turner06978cc2014-04-03 15:55:43 +0200895target_ulong helper_mftc0_tcschefback(CPUMIPSState *env)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800896{
897 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
David 'Digit' Turner06978cc2014-04-03 15:55:43 +0200898 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800899
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +0100900 if (other_tc == other->current_tc)
901 return other->active_tc.CP0_TCScheFBack;
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800902 else
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +0100903 return other->tcs[other_tc].CP0_TCScheFBack;
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800904}
905
David 'Digit' Turner06978cc2014-04-03 15:55:43 +0200906target_ulong helper_mfc0_count(CPUMIPSState *env)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800907{
908 return (int32_t)cpu_mips_get_count(env);
909}
910
David 'Digit' Turner06978cc2014-04-03 15:55:43 +0200911target_ulong helper_mftc0_entryhi(CPUMIPSState *env)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800912{
913 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
David 'Digit' Turner06978cc2014-04-03 15:55:43 +0200914 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800915
David 'Digit' Turner811b0292014-03-20 18:08:55 +0100916 return other->CP0_EntryHi;
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800917}
918
David 'Digit' Turner06978cc2014-04-03 15:55:43 +0200919target_ulong helper_mftc0_status(CPUMIPSState *env)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800920{
921 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
David 'Digit' Turner06978cc2014-04-03 15:55:43 +0200922 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800923
David 'Digit' Turner811b0292014-03-20 18:08:55 +0100924 return other->CP0_Status;
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800925}
926
David 'Digit' Turner06978cc2014-04-03 15:55:43 +0200927target_ulong helper_mfc0_lladdr(CPUMIPSState *env)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800928{
929 return (int32_t)(env->lladdr >> env->CP0_LLAddr_shift);
930}
931
David 'Digit' Turner06978cc2014-04-03 15:55:43 +0200932target_ulong helper_mfc0_watchlo(CPUMIPSState *env, uint32_t sel)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800933{
934 return (int32_t)env->CP0_WatchLo[sel];
935}
936
David 'Digit' Turner06978cc2014-04-03 15:55:43 +0200937target_ulong helper_mfc0_watchhi(CPUMIPSState *env, uint32_t sel)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800938{
939 return env->CP0_WatchHi[sel];
940}
941
David 'Digit' Turner06978cc2014-04-03 15:55:43 +0200942target_ulong helper_mfc0_debug(CPUMIPSState *env)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800943{
944 target_ulong t0 = env->CP0_Debug;
945 if (env->hflags & MIPS_HFLAG_DM)
946 t0 |= 1 << CP0DB_DM;
947
948 return t0;
949}
950
David 'Digit' Turner06978cc2014-04-03 15:55:43 +0200951target_ulong helper_mftc0_debug(CPUMIPSState *env)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800952{
953 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
954 int32_t tcstatus;
David 'Digit' Turner06978cc2014-04-03 15:55:43 +0200955 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800956
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +0100957 if (other_tc == other->current_tc)
958 tcstatus = other->active_tc.CP0_Debug_tcstatus;
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800959 else
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +0100960 tcstatus = other->tcs[other_tc].CP0_Debug_tcstatus;
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800961
962 /* XXX: Might be wrong, check with EJTAG spec. */
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +0100963 return (other->CP0_Debug & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800964 (tcstatus & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
965}
966
967#if defined(TARGET_MIPS64)
David 'Digit' Turner06978cc2014-04-03 15:55:43 +0200968target_ulong helper_dmfc0_tcrestart(CPUMIPSState *env)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800969{
970 return env->active_tc.PC;
971}
972
David 'Digit' Turner06978cc2014-04-03 15:55:43 +0200973target_ulong helper_dmfc0_tchalt(CPUMIPSState *env)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800974{
975 return env->active_tc.CP0_TCHalt;
976}
977
David 'Digit' Turner06978cc2014-04-03 15:55:43 +0200978target_ulong helper_dmfc0_tccontext(CPUMIPSState *env)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800979{
980 return env->active_tc.CP0_TCContext;
981}
982
David 'Digit' Turner06978cc2014-04-03 15:55:43 +0200983target_ulong helper_dmfc0_tcschedule(CPUMIPSState *env)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800984{
985 return env->active_tc.CP0_TCSchedule;
986}
987
David 'Digit' Turner06978cc2014-04-03 15:55:43 +0200988target_ulong helper_dmfc0_tcschefback(CPUMIPSState *env)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800989{
990 return env->active_tc.CP0_TCScheFBack;
991}
992
David 'Digit' Turner06978cc2014-04-03 15:55:43 +0200993target_ulong helper_dmfc0_lladdr(CPUMIPSState *env)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800994{
995 return env->lladdr >> env->CP0_LLAddr_shift;
996}
997
David 'Digit' Turner06978cc2014-04-03 15:55:43 +0200998target_ulong helper_dmfc0_watchlo(CPUMIPSState *env, uint32_t sel)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -0800999{
1000 return env->CP0_WatchLo[sel];
1001}
1002#endif /* TARGET_MIPS64 */
1003
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001004void helper_mtc0_index(CPUMIPSState *env, target_ulong arg1)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001005{
1006 int num = 1;
1007 unsigned int tmp = env->tlb->nb_tlb;
1008
1009 do {
1010 tmp >>= 1;
1011 num <<= 1;
1012 } while (tmp);
1013 env->CP0_Index = (env->CP0_Index & 0x80000000) | (arg1 & (num - 1));
1014}
1015
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001016void helper_mtc0_mvpcontrol(CPUMIPSState *env, target_ulong arg1)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001017{
1018 uint32_t mask = 0;
1019 uint32_t newval;
1020
1021 if (env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP))
1022 mask |= (1 << CP0MVPCo_CPA) | (1 << CP0MVPCo_VPC) |
1023 (1 << CP0MVPCo_EVP);
1024 if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
1025 mask |= (1 << CP0MVPCo_STLB);
1026 newval = (env->mvp->CP0_MVPControl & ~mask) | (arg1 & mask);
1027
1028 // TODO: Enable/disable shared TLB, enable/disable VPEs.
1029
1030 env->mvp->CP0_MVPControl = newval;
1031}
1032
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001033void helper_mtc0_vpecontrol(CPUMIPSState *env, target_ulong arg1)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001034{
1035 uint32_t mask;
1036 uint32_t newval;
1037
1038 mask = (1 << CP0VPECo_YSI) | (1 << CP0VPECo_GSI) |
1039 (1 << CP0VPECo_TE) | (0xff << CP0VPECo_TargTC);
1040 newval = (env->CP0_VPEControl & ~mask) | (arg1 & mask);
1041
1042 /* Yield scheduler intercept not implemented. */
1043 /* Gating storage scheduler intercept not implemented. */
1044
1045 // TODO: Enable/disable TCs.
1046
1047 env->CP0_VPEControl = newval;
1048}
1049
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001050void helper_mtc0_vpeconf0(CPUMIPSState *env, target_ulong arg1)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001051{
1052 uint32_t mask = 0;
1053 uint32_t newval;
1054
1055 if (env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) {
1056 if (env->CP0_VPEConf0 & (1 << CP0VPEC0_VPA))
1057 mask |= (0xff << CP0VPEC0_XTC);
1058 mask |= (1 << CP0VPEC0_MVP) | (1 << CP0VPEC0_VPA);
1059 }
1060 newval = (env->CP0_VPEConf0 & ~mask) | (arg1 & mask);
1061
1062 // TODO: TC exclusive handling due to ERL/EXL.
1063
1064 env->CP0_VPEConf0 = newval;
1065}
1066
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001067void helper_mtc0_vpeconf1(CPUMIPSState *env, target_ulong arg1)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001068{
1069 uint32_t mask = 0;
1070 uint32_t newval;
1071
1072 if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
1073 mask |= (0xff << CP0VPEC1_NCX) | (0xff << CP0VPEC1_NCP2) |
1074 (0xff << CP0VPEC1_NCP1);
1075 newval = (env->CP0_VPEConf1 & ~mask) | (arg1 & mask);
1076
1077 /* UDI not implemented. */
1078 /* CP2 not implemented. */
1079
1080 // TODO: Handle FPU (CP1) binding.
1081
1082 env->CP0_VPEConf1 = newval;
1083}
1084
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001085void helper_mtc0_yqmask(CPUMIPSState *env, target_ulong arg1)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001086{
1087 /* Yield qualifier inputs not implemented. */
1088 env->CP0_YQMask = 0x00000000;
1089}
1090
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001091void helper_mtc0_vpeopt(CPUMIPSState *env, target_ulong arg1)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001092{
1093 env->CP0_VPEOpt = arg1 & 0x0000ffff;
1094}
1095
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001096void helper_mtc0_entrylo0(CPUMIPSState *env, target_ulong arg1)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001097{
1098 /* Large physaddr (PABITS) not implemented */
1099 /* 1k pages not implemented */
1100 env->CP0_EntryLo0 = arg1 & 0x3FFFFFFF;
1101}
1102
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001103void helper_mtc0_tcstatus(CPUMIPSState *env, target_ulong arg1)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001104{
1105 uint32_t mask = env->CP0_TCStatus_rw_bitmask;
1106 uint32_t newval;
1107
1108 newval = (env->active_tc.CP0_TCStatus & ~mask) | (arg1 & mask);
1109
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001110 env->active_tc.CP0_TCStatus = newval;
David 'Digit' Turner811b0292014-03-20 18:08:55 +01001111 sync_c0_tcstatus(env, env->current_tc, newval);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001112}
1113
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001114void helper_mttc0_tcstatus(CPUMIPSState *env, target_ulong arg1)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001115{
1116 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001117 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001118
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +01001119 if (other_tc == other->current_tc)
1120 other->active_tc.CP0_TCStatus = arg1;
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001121 else
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +01001122 other->tcs[other_tc].CP0_TCStatus = arg1;
David 'Digit' Turner811b0292014-03-20 18:08:55 +01001123 sync_c0_tcstatus(other, other_tc, arg1);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001124}
1125
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001126void helper_mtc0_tcbind(CPUMIPSState *env, target_ulong arg1)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001127{
1128 uint32_t mask = (1 << CP0TCBd_TBE);
1129 uint32_t newval;
1130
1131 if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
1132 mask |= (1 << CP0TCBd_CurVPE);
1133 newval = (env->active_tc.CP0_TCBind & ~mask) | (arg1 & mask);
1134 env->active_tc.CP0_TCBind = newval;
1135}
1136
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001137void helper_mttc0_tcbind(CPUMIPSState *env, target_ulong arg1)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001138{
1139 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1140 uint32_t mask = (1 << CP0TCBd_TBE);
1141 uint32_t newval;
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001142 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001143
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +01001144 if (other->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001145 mask |= (1 << CP0TCBd_CurVPE);
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +01001146 if (other_tc == other->current_tc) {
1147 newval = (other->active_tc.CP0_TCBind & ~mask) | (arg1 & mask);
1148 other->active_tc.CP0_TCBind = newval;
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001149 } else {
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +01001150 newval = (other->tcs[other_tc].CP0_TCBind & ~mask) | (arg1 & mask);
1151 other->tcs[other_tc].CP0_TCBind = newval;
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001152 }
1153}
1154
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001155void helper_mtc0_tcrestart(CPUMIPSState *env, target_ulong arg1)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001156{
1157 env->active_tc.PC = arg1;
1158 env->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
1159 env->lladdr = 0ULL;
1160 /* MIPS16 not implemented. */
1161}
1162
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001163void helper_mttc0_tcrestart(CPUMIPSState *env, target_ulong arg1)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001164{
1165 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001166 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001167
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +01001168 if (other_tc == other->current_tc) {
1169 other->active_tc.PC = arg1;
1170 other->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
1171 other->lladdr = 0ULL;
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001172 /* MIPS16 not implemented. */
1173 } else {
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +01001174 other->tcs[other_tc].PC = arg1;
1175 other->tcs[other_tc].CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
1176 other->lladdr = 0ULL;
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001177 /* MIPS16 not implemented. */
1178 }
1179}
1180
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001181void helper_mtc0_tchalt(CPUMIPSState *env, target_ulong arg1)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001182{
1183 env->active_tc.CP0_TCHalt = arg1 & 0x1;
1184
1185 // TODO: Halt TC / Restart (if allocated+active) TC.
1186}
1187
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001188void helper_mttc0_tchalt(CPUMIPSState *env, target_ulong arg1)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001189{
1190 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001191 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001192
1193 // TODO: Halt TC / Restart (if allocated+active) TC.
1194
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +01001195 if (other_tc == other->current_tc)
1196 other->active_tc.CP0_TCHalt = arg1;
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001197 else
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +01001198 other->tcs[other_tc].CP0_TCHalt = arg1;
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001199}
1200
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001201void helper_mtc0_tccontext(CPUMIPSState *env, target_ulong arg1)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001202{
1203 env->active_tc.CP0_TCContext = arg1;
1204}
1205
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001206void helper_mttc0_tccontext(CPUMIPSState *env, target_ulong arg1)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001207{
1208 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001209 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001210
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +01001211 if (other_tc == other->current_tc)
1212 other->active_tc.CP0_TCContext = arg1;
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001213 else
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +01001214 other->tcs[other_tc].CP0_TCContext = arg1;
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001215}
1216
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001217void helper_mtc0_tcschedule(CPUMIPSState *env, target_ulong arg1)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001218{
1219 env->active_tc.CP0_TCSchedule = arg1;
1220}
1221
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001222void helper_mttc0_tcschedule(CPUMIPSState *env, target_ulong arg1)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001223{
1224 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001225 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001226
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +01001227 if (other_tc == other->current_tc)
1228 other->active_tc.CP0_TCSchedule = arg1;
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001229 else
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +01001230 other->tcs[other_tc].CP0_TCSchedule = arg1;
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001231}
1232
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001233void helper_mtc0_tcschefback(CPUMIPSState *env, target_ulong arg1)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001234{
1235 env->active_tc.CP0_TCScheFBack = arg1;
1236}
1237
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001238void helper_mttc0_tcschefback(CPUMIPSState *env, target_ulong arg1)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001239{
1240 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001241 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001242
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +01001243 if (other_tc == other->current_tc)
1244 other->active_tc.CP0_TCScheFBack = arg1;
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001245 else
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +01001246 other->tcs[other_tc].CP0_TCScheFBack = arg1;
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001247}
1248
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001249void helper_mtc0_entrylo1(CPUMIPSState *env, target_ulong arg1)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001250{
1251 /* Large physaddr (PABITS) not implemented */
1252 /* 1k pages not implemented */
1253 env->CP0_EntryLo1 = arg1 & 0x3FFFFFFF;
1254}
1255
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001256void helper_mtc0_context(CPUMIPSState *env, target_ulong arg1)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001257{
1258 env->CP0_Context = (env->CP0_Context & 0x007FFFFF) | (arg1 & ~0x007FFFFF);
1259}
1260
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001261void helper_mtc0_pagemask(CPUMIPSState *env, target_ulong arg1)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001262{
1263 /* 1k pages not implemented */
1264 env->CP0_PageMask = arg1 & (0x1FFFFFFF & (TARGET_PAGE_MASK << 1));
1265}
1266
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001267void helper_mtc0_pagegrain(CPUMIPSState *env, target_ulong arg1)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001268{
1269 /* SmartMIPS not implemented */
1270 /* Large physaddr (PABITS) not implemented */
1271 /* 1k pages not implemented */
1272 env->CP0_PageGrain = 0;
1273}
1274
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001275void helper_mtc0_wired(CPUMIPSState *env, target_ulong arg1)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001276{
1277 env->CP0_Wired = arg1 % env->tlb->nb_tlb;
1278}
1279
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001280void helper_mtc0_srsconf0(CPUMIPSState *env, target_ulong arg1)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001281{
1282 env->CP0_SRSConf0 |= arg1 & env->CP0_SRSConf0_rw_bitmask;
1283}
1284
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001285void helper_mtc0_srsconf1(CPUMIPSState *env, target_ulong arg1)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001286{
1287 env->CP0_SRSConf1 |= arg1 & env->CP0_SRSConf1_rw_bitmask;
1288}
1289
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001290void helper_mtc0_srsconf2(CPUMIPSState *env, target_ulong arg1)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001291{
1292 env->CP0_SRSConf2 |= arg1 & env->CP0_SRSConf2_rw_bitmask;
1293}
1294
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001295void helper_mtc0_srsconf3(CPUMIPSState *env, target_ulong arg1)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001296{
1297 env->CP0_SRSConf3 |= arg1 & env->CP0_SRSConf3_rw_bitmask;
1298}
1299
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001300void helper_mtc0_srsconf4(CPUMIPSState *env, target_ulong arg1)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001301{
1302 env->CP0_SRSConf4 |= arg1 & env->CP0_SRSConf4_rw_bitmask;
1303}
1304
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001305void helper_mtc0_hwrena(CPUMIPSState *env, target_ulong arg1)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001306{
1307 env->CP0_HWREna = arg1 & 0x0000000F;
1308}
1309
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001310void helper_mtc0_count(CPUMIPSState *env, target_ulong arg1)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001311{
1312 cpu_mips_store_count(env, arg1);
1313}
1314
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001315void helper_mtc0_entryhi(CPUMIPSState *env, target_ulong arg1)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001316{
1317 target_ulong old, val;
1318
1319 /* 1k pages not implemented */
1320 val = arg1 & ((TARGET_PAGE_MASK << 1) | 0xFF);
1321#if defined(TARGET_MIPS64)
1322 val &= env->SEGMask;
1323#endif
1324 old = env->CP0_EntryHi;
1325 env->CP0_EntryHi = val;
1326 if (env->CP0_Config3 & (1 << CP0C3_MT)) {
David 'Digit' Turner811b0292014-03-20 18:08:55 +01001327 sync_c0_entryhi(env, env->current_tc);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001328 }
1329 /* If the ASID changes, flush qemu's TLB. */
1330 if ((old & 0xFF) != (val & 0xFF))
1331 cpu_mips_tlb_flush(env, 1);
1332}
1333
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001334void helper_mttc0_entryhi(CPUMIPSState *env, target_ulong arg1)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001335{
1336 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001337 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001338
David 'Digit' Turner811b0292014-03-20 18:08:55 +01001339 other->CP0_EntryHi = arg1;
1340 sync_c0_entryhi(other, other_tc);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001341}
1342
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001343void helper_mtc0_compare(CPUMIPSState *env, target_ulong arg1)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001344{
1345 cpu_mips_store_compare(env, arg1);
1346}
1347
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001348void helper_mtc0_status(CPUMIPSState *env, target_ulong arg1)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001349{
1350 uint32_t val, old;
1351 uint32_t mask = env->CP0_Status_rw_bitmask;
1352
1353 val = arg1 & mask;
1354 old = env->CP0_Status;
1355 env->CP0_Status = (env->CP0_Status & ~mask) | val;
David 'Digit' Turner811b0292014-03-20 18:08:55 +01001356 if (env->CP0_Config3 & (1 << CP0C3_MT)) {
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001357 sync_c0_status(env, env, env->current_tc);
David 'Digit' Turner811b0292014-03-20 18:08:55 +01001358 } else {
1359 compute_hflags(env);
1360 }
1361
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001362 if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
1363 qemu_log("Status %08x (%08x) => %08x (%08x) Cause %08x",
1364 old, old & env->CP0_Cause & CP0Ca_IP_mask,
1365 val, val & env->CP0_Cause & CP0Ca_IP_mask,
1366 env->CP0_Cause);
1367 switch (env->hflags & MIPS_HFLAG_KSU) {
1368 case MIPS_HFLAG_UM: qemu_log(", UM\n"); break;
1369 case MIPS_HFLAG_SM: qemu_log(", SM\n"); break;
1370 case MIPS_HFLAG_KM: qemu_log("\n"); break;
1371 default: cpu_abort(env, "Invalid MMU mode!\n"); break;
1372 }
1373 }
1374 cpu_mips_update_irq(env);
1375}
1376
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001377void helper_mttc0_status(CPUMIPSState *env, target_ulong arg1)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001378{
1379 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001380 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001381
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +01001382 other->CP0_Status = arg1 & ~0xf1000018;
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001383 sync_c0_status(env, other, other_tc);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001384}
1385
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001386void helper_mtc0_intctl(CPUMIPSState *env, target_ulong arg1)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001387{
1388 /* vectored interrupts not implemented, no performance counters. */
1389 env->CP0_IntCtl = (env->CP0_IntCtl & ~0x000002e0) | (arg1 & 0x000002e0);
1390}
1391
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001392void helper_mtc0_srsctl(CPUMIPSState *env, target_ulong arg1)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001393{
1394 uint32_t mask = (0xf << CP0SRSCtl_ESS) | (0xf << CP0SRSCtl_PSS);
1395 env->CP0_SRSCtl = (env->CP0_SRSCtl & ~mask) | (arg1 & mask);
1396}
1397
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001398void helper_mtc0_cause(CPUMIPSState *env, target_ulong arg1)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001399{
1400 uint32_t mask = 0x00C00300;
1401 uint32_t old = env->CP0_Cause;
1402
1403 if (env->insn_flags & ISA_MIPS32R2)
1404 mask |= 1 << CP0Ca_DC;
1405
1406 env->CP0_Cause = (env->CP0_Cause & ~mask) | (arg1 & mask);
1407
1408 if ((old ^ env->CP0_Cause) & (1 << CP0Ca_DC)) {
1409 if (env->CP0_Cause & (1 << CP0Ca_DC))
1410 cpu_mips_stop_count(env);
1411 else
1412 cpu_mips_start_count(env);
1413 }
1414
1415 /* Handle the software interrupt as an hardware one, as they
1416 are very similar */
1417 if (arg1 & CP0Ca_IP_mask) {
1418 cpu_mips_update_irq(env);
1419 }
1420}
1421
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001422void helper_mtc0_ebase(CPUMIPSState *env, target_ulong arg1)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001423{
1424 /* vectored interrupts not implemented */
1425 /* Multi-CPU not implemented */
1426 env->CP0_EBase = 0x80000000 | (arg1 & 0x3FFFF000);
1427}
1428
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001429void helper_mtc0_config0(CPUMIPSState *env, target_ulong arg1)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001430{
1431 env->CP0_Config0 = (env->CP0_Config0 & 0x81FFFFF8) | (arg1 & 0x00000007);
1432}
1433
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001434void helper_mtc0_config2(CPUMIPSState *env, target_ulong arg1)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001435{
1436 /* tertiary/secondary caches not implemented */
1437 env->CP0_Config2 = (env->CP0_Config2 & 0x8FFF0FFF);
1438}
1439
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001440void helper_mtc0_lladdr(CPUMIPSState *env, target_ulong arg1)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001441{
1442 target_long mask = env->CP0_LLAddr_rw_bitmask;
1443 arg1 = arg1 << env->CP0_LLAddr_shift;
1444 env->lladdr = (env->lladdr & ~mask) | (arg1 & mask);
1445}
1446
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001447void helper_mtc0_watchlo(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001448{
1449 /* Watch exceptions for instructions, data loads, data stores
1450 not implemented. */
1451 env->CP0_WatchLo[sel] = (arg1 & ~0x7);
1452}
1453
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001454void helper_mtc0_watchhi(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001455{
1456 env->CP0_WatchHi[sel] = (arg1 & 0x40FF0FF8);
1457 env->CP0_WatchHi[sel] &= ~(env->CP0_WatchHi[sel] & arg1 & 0x7);
1458}
1459
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001460void helper_mtc0_xcontext(CPUMIPSState *env, target_ulong arg1)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001461{
1462 target_ulong mask = (1ULL << (env->SEGBITS - 7)) - 1;
1463 env->CP0_XContext = (env->CP0_XContext & mask) | (arg1 & ~mask);
1464}
1465
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001466void helper_mtc0_framemask(CPUMIPSState *env, target_ulong arg1)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001467{
1468 env->CP0_Framemask = arg1; /* XXX */
1469}
1470
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001471void helper_mtc0_debug(CPUMIPSState *env, target_ulong arg1)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001472{
1473 env->CP0_Debug = (env->CP0_Debug & 0x8C03FC1F) | (arg1 & 0x13300120);
1474 if (arg1 & (1 << CP0DB_DM))
1475 env->hflags |= MIPS_HFLAG_DM;
1476 else
1477 env->hflags &= ~MIPS_HFLAG_DM;
1478}
1479
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001480void helper_mttc0_debug(CPUMIPSState *env, target_ulong arg1)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001481{
1482 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1483 uint32_t val = arg1 & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt));
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001484 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001485
1486 /* XXX: Might be wrong, check with EJTAG spec. */
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +01001487 if (other_tc == other->current_tc)
1488 other->active_tc.CP0_Debug_tcstatus = val;
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001489 else
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +01001490 other->tcs[other_tc].CP0_Debug_tcstatus = val;
1491 other->CP0_Debug = (other->CP0_Debug &
1492 ((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001493 (arg1 & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
1494}
1495
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001496void helper_mtc0_performance0(CPUMIPSState *env, target_ulong arg1)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001497{
1498 env->CP0_Performance0 = arg1 & 0x000007ff;
1499}
1500
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001501void helper_mtc0_taglo(CPUMIPSState *env, target_ulong arg1)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001502{
1503 env->CP0_TagLo = arg1 & 0xFFFFFCF6;
1504}
1505
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001506void helper_mtc0_datalo(CPUMIPSState *env, target_ulong arg1)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001507{
1508 env->CP0_DataLo = arg1; /* XXX */
1509}
1510
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001511void helper_mtc0_taghi(CPUMIPSState *env, target_ulong arg1)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001512{
1513 env->CP0_TagHi = arg1; /* XXX */
1514}
1515
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001516void helper_mtc0_datahi(CPUMIPSState *env, target_ulong arg1)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001517{
1518 env->CP0_DataHi = arg1; /* XXX */
1519}
1520
1521/* MIPS MT functions */
David 'Digit' Turner26efe752014-04-03 15:59:28 +02001522target_ulong helper_mftgpr(CPUMIPSState *env, uint32_t sel)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001523{
1524 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001525 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001526
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +01001527 if (other_tc == other->current_tc)
1528 return other->active_tc.gpr[sel];
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001529 else
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +01001530 return other->tcs[other_tc].gpr[sel];
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001531}
1532
David 'Digit' Turner26efe752014-04-03 15:59:28 +02001533target_ulong helper_mftlo(CPUMIPSState *env, uint32_t sel)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001534{
1535 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001536 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001537
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +01001538 if (other_tc == other->current_tc)
1539 return other->active_tc.LO[sel];
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001540 else
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +01001541 return other->tcs[other_tc].LO[sel];
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001542}
1543
David 'Digit' Turner26efe752014-04-03 15:59:28 +02001544target_ulong helper_mfthi(CPUMIPSState *env, uint32_t sel)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001545{
1546 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001547 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001548
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +01001549 if (other_tc == other->current_tc)
1550 return other->active_tc.HI[sel];
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001551 else
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +01001552 return other->tcs[other_tc].HI[sel];
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001553}
1554
David 'Digit' Turner26efe752014-04-03 15:59:28 +02001555target_ulong helper_mftacx(CPUMIPSState *env, uint32_t sel)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001556{
1557 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001558 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001559
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +01001560 if (other_tc == other->current_tc)
1561 return other->active_tc.ACX[sel];
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001562 else
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +01001563 return other->tcs[other_tc].ACX[sel];
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001564}
1565
David 'Digit' Turner26efe752014-04-03 15:59:28 +02001566target_ulong helper_mftdsp(CPUMIPSState *env)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001567{
1568 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001569 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001570
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +01001571 if (other_tc == other->current_tc)
1572 return other->active_tc.DSPControl;
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001573 else
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +01001574 return other->tcs[other_tc].DSPControl;
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001575}
1576
David 'Digit' Turner26efe752014-04-03 15:59:28 +02001577void helper_mttgpr(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001578{
1579 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001580 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001581
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +01001582 if (other_tc == other->current_tc)
1583 other->active_tc.gpr[sel] = arg1;
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001584 else
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +01001585 other->tcs[other_tc].gpr[sel] = arg1;
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001586}
1587
David 'Digit' Turner26efe752014-04-03 15:59:28 +02001588void helper_mttlo(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001589{
1590 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001591 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001592
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +01001593 if (other_tc == other->current_tc)
1594 other->active_tc.LO[sel] = arg1;
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001595 else
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +01001596 other->tcs[other_tc].LO[sel] = arg1;
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001597}
1598
David 'Digit' Turner26efe752014-04-03 15:59:28 +02001599void helper_mtthi(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001600{
1601 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001602 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001603
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +01001604 if (other_tc == other->current_tc)
1605 other->active_tc.HI[sel] = arg1;
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001606 else
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +01001607 other->tcs[other_tc].HI[sel] = arg1;
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001608}
1609
David 'Digit' Turner26efe752014-04-03 15:59:28 +02001610void helper_mttacx(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001611{
1612 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001613 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001614
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +01001615 if (other_tc == other->current_tc)
1616 other->active_tc.ACX[sel] = arg1;
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001617 else
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +01001618 other->tcs[other_tc].ACX[sel] = arg1;
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001619}
1620
David 'Digit' Turner26efe752014-04-03 15:59:28 +02001621void helper_mttdsp(CPUMIPSState *env, target_ulong arg1)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001622{
1623 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
David 'Digit' Turner06978cc2014-04-03 15:55:43 +02001624 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001625
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +01001626 if (other_tc == other->current_tc)
1627 other->active_tc.DSPControl = arg1;
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001628 else
David 'Digit' Turnerc8ba4e82014-03-20 18:03:59 +01001629 other->tcs[other_tc].DSPControl = arg1;
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001630}
1631
1632/* MIPS MT functions */
David 'Digit' Turner26efe752014-04-03 15:59:28 +02001633target_ulong helper_dmt(void)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001634{
1635 // TODO
David 'Digit' Turner26efe752014-04-03 15:59:28 +02001636 return 0;
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001637}
1638
David 'Digit' Turner26efe752014-04-03 15:59:28 +02001639target_ulong helper_emt(void)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001640{
1641 // TODO
David 'Digit' Turner26efe752014-04-03 15:59:28 +02001642 return 0;
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001643}
1644
David 'Digit' Turner26efe752014-04-03 15:59:28 +02001645target_ulong helper_dvpe(CPUMIPSState *env)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001646{
1647 // TODO
David 'Digit' Turner26efe752014-04-03 15:59:28 +02001648 return 0;
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001649}
1650
David 'Digit' Turner26efe752014-04-03 15:59:28 +02001651target_ulong helper_evpe(CPUMIPSState *env)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001652{
1653 // TODO
David 'Digit' Turner26efe752014-04-03 15:59:28 +02001654 return 0;
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001655}
1656#endif /* !CONFIG_USER_ONLY */
1657
1658void helper_fork(target_ulong arg1, target_ulong arg2)
1659{
1660 // arg1 = rt, arg2 = rs
1661 arg1 = 0;
1662 // TODO: store to TC register
1663}
1664
David 'Digit' Turner26efe752014-04-03 15:59:28 +02001665target_ulong helper_yield(CPUMIPSState *env, target_ulong arg)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001666{
David 'Digit' Turner26efe752014-04-03 15:59:28 +02001667 target_long arg1 = arg;
1668
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001669 if (arg1 < 0) {
1670 /* No scheduling policy implemented. */
1671 if (arg1 != -2) {
1672 if (env->CP0_VPEControl & (1 << CP0VPECo_YSI) &&
1673 env->active_tc.CP0_TCStatus & (1 << CP0TCSt_DT)) {
1674 env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
1675 env->CP0_VPEControl |= 4 << CP0VPECo_EXCPT;
David 'Digit' Turner6480c962014-04-03 12:38:04 +02001676 helper_raise_exception(env, EXCP_THREAD);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001677 }
1678 }
1679 } else if (arg1 == 0) {
1680 if (0 /* TODO: TC underflow */) {
1681 env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
David 'Digit' Turner6480c962014-04-03 12:38:04 +02001682 helper_raise_exception(env, EXCP_THREAD);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001683 } else {
1684 // TODO: Deallocate TC
1685 }
1686 } else if (arg1 > 0) {
1687 /* Yield qualifier inputs not implemented. */
1688 env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
1689 env->CP0_VPEControl |= 2 << CP0VPECo_EXCPT;
David 'Digit' Turner6480c962014-04-03 12:38:04 +02001690 helper_raise_exception(env, EXCP_THREAD);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001691 }
1692 return env->CP0_YQMask;
1693}
1694
1695#ifndef CONFIG_USER_ONLY
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01001696static void inline r4k_invalidate_tlb_shadow (CPUMIPSState *env, int idx)
Chris Dearman55ff3182012-08-03 14:35:52 -07001697{
1698 r4k_tlb_t *tlb;
1699 uint8_t ASID = env->CP0_EntryHi & 0xFF;
1700
1701 tlb = &env->tlb->mmu.r4k.tlb[idx];
1702 /* The qemu TLB is flushed when the ASID changes, so no need to
1703 flush these entries again. */
1704 if (tlb->G == 0 && tlb->ASID != ASID) {
1705 return;
1706 }
1707}
1708
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01001709static void inline r4k_invalidate_tlb (CPUMIPSState *env, int idx)
Chris Dearman55ff3182012-08-03 14:35:52 -07001710{
1711 r4k_tlb_t *tlb;
1712 target_ulong addr;
1713 target_ulong end;
1714 uint8_t ASID = env->CP0_EntryHi & 0xFF;
1715 target_ulong mask;
1716
1717 tlb = &env->tlb->mmu.r4k.tlb[idx];
1718 /* The qemu TLB is flushed when the ASID changes, so no need to
1719 flush these entries again. */
1720 if (tlb->G == 0 && tlb->ASID != ASID) {
1721 return;
1722 }
1723
1724 /* 1k pages are not supported. */
1725 mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
1726 if (tlb->V0) {
1727 addr = tlb->VPN & ~mask;
1728#if defined(TARGET_MIPS64)
1729 if (addr >= (0xFFFFFFFF80000000ULL & env->SEGMask)) {
1730 addr |= 0x3FFFFF0000000000ULL;
1731 }
1732#endif
1733 end = addr | (mask >> 1);
1734 while (addr < end) {
1735 tlb_flush_page (env, addr);
1736 addr += TARGET_PAGE_SIZE;
1737 }
1738 }
1739 if (tlb->V1) {
1740 addr = (tlb->VPN & ~mask) | ((mask >> 1) + 1);
1741#if defined(TARGET_MIPS64)
1742 if (addr >= (0xFFFFFFFF80000000ULL & env->SEGMask)) {
1743 addr |= 0x3FFFFF0000000000ULL;
1744 }
1745#endif
1746 end = addr | mask;
1747 while (addr - 1 < end) {
1748 tlb_flush_page (env, addr);
1749 addr += TARGET_PAGE_SIZE;
1750 }
1751 }
1752}
1753
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001754/* TLB management */
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01001755void cpu_mips_tlb_flush (CPUMIPSState *env, int flush_global)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001756{
1757 /* Flush qemu's TLB and discard all shadowed entries. */
1758 tlb_flush (env, flush_global);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001759}
1760
David 'Digit' Turner758fa082014-04-03 12:29:21 +02001761static void r4k_fill_tlb(CPUMIPSState *env, int idx)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001762{
1763 r4k_tlb_t *tlb;
1764
1765 /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */
1766 tlb = &env->tlb->mmu.r4k.tlb[idx];
1767 tlb->VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1);
1768#if defined(TARGET_MIPS64)
1769 tlb->VPN &= env->SEGMask;
1770#endif
1771 tlb->ASID = env->CP0_EntryHi & 0xFF;
1772 tlb->PageMask = env->CP0_PageMask;
1773 tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
1774 tlb->V0 = (env->CP0_EntryLo0 & 2) != 0;
1775 tlb->D0 = (env->CP0_EntryLo0 & 4) != 0;
1776 tlb->C0 = (env->CP0_EntryLo0 >> 3) & 0x7;
1777 tlb->PFN[0] = (env->CP0_EntryLo0 >> 6) << 12;
1778 tlb->V1 = (env->CP0_EntryLo1 & 2) != 0;
1779 tlb->D1 = (env->CP0_EntryLo1 & 4) != 0;
1780 tlb->C1 = (env->CP0_EntryLo1 >> 3) & 0x7;
1781 tlb->PFN[1] = (env->CP0_EntryLo1 >> 6) << 12;
1782}
1783
David 'Digit' Turner758fa082014-04-03 12:29:21 +02001784void r4k_helper_ptw_tlbrefill(CPUMIPSState *env)
Chris Dearman55ff3182012-08-03 14:35:52 -07001785{
Chris Dearman55ff3182012-08-03 14:35:52 -07001786 /* Do TLB load on behalf of Page Table Walk */
1787 int r = cpu_mips_get_random(env);
1788 r4k_invalidate_tlb_shadow(env, r);
David 'Digit' Turner758fa082014-04-03 12:29:21 +02001789 r4k_fill_tlb(env, r);
Chris Dearman55ff3182012-08-03 14:35:52 -07001790}
1791
David 'Digit' Turner758fa082014-04-03 12:29:21 +02001792void r4k_helper_tlbwi (CPUMIPSState *env)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001793{
Chris Dearman55ff3182012-08-03 14:35:52 -07001794 r4k_tlb_t *tlb;
1795 target_ulong tag;
1796 target_ulong VPN;
1797 target_ulong mask;
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001798
Chris Dearman55ff3182012-08-03 14:35:52 -07001799 /* If tlbwi is trying to upgrading access permissions on current entry,
1800 * we do not need to flush tlb hash table.
1801 */
1802 tlb = &env->tlb->mmu.r4k.tlb[env->CP0_Index % env->tlb->nb_tlb];
1803 mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
1804 tag = env->CP0_EntryHi & ~mask;
1805 VPN = tlb->VPN & ~mask;
1806 if (VPN == tag)
1807 {
1808 if (tlb->ASID == (env->CP0_EntryHi & 0xFF))
1809 {
1810 tlb->V0 = (env->CP0_EntryLo0 & 2) != 0;
1811 tlb->D0 = (env->CP0_EntryLo0 & 4) != 0;
1812 tlb->C0 = (env->CP0_EntryLo0 >> 3) & 0x7;
1813 tlb->PFN[0] = (env->CP0_EntryLo0 >> 6) << 12;
1814 tlb->V1 = (env->CP0_EntryLo1 & 2) != 0;
1815 tlb->D1 = (env->CP0_EntryLo1 & 4) != 0;
1816 tlb->C1 = (env->CP0_EntryLo1 >> 3) & 0x7;
1817 tlb->PFN[1] = (env->CP0_EntryLo1 >> 6) << 12;
1818 return;
1819 }
1820 }
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001821
Chris Dearman55ff3182012-08-03 14:35:52 -07001822 /*flush all the tlb cache */
1823 cpu_mips_tlb_flush (env, 1);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001824
Chris Dearman55ff3182012-08-03 14:35:52 -07001825 r4k_invalidate_tlb(env, env->CP0_Index % env->tlb->nb_tlb);
David 'Digit' Turner758fa082014-04-03 12:29:21 +02001826 r4k_fill_tlb(env, env->CP0_Index % env->tlb->nb_tlb);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001827}
1828
David 'Digit' Turner758fa082014-04-03 12:29:21 +02001829void r4k_helper_tlbwr (CPUMIPSState *env)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001830{
1831 int r = cpu_mips_get_random(env);
1832
Chris Dearman55ff3182012-08-03 14:35:52 -07001833 r4k_invalidate_tlb_shadow(env, r);
David 'Digit' Turner758fa082014-04-03 12:29:21 +02001834 r4k_fill_tlb(env, r);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001835}
1836
David 'Digit' Turner758fa082014-04-03 12:29:21 +02001837void r4k_helper_tlbp(CPUMIPSState *env)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001838{
1839 r4k_tlb_t *tlb;
1840 target_ulong mask;
1841 target_ulong tag;
1842 target_ulong VPN;
1843 uint8_t ASID;
1844 int i;
1845
1846 ASID = env->CP0_EntryHi & 0xFF;
1847 for (i = 0; i < env->tlb->nb_tlb; i++) {
1848 tlb = &env->tlb->mmu.r4k.tlb[i];
1849 /* 1k pages are not supported. */
1850 mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
1851 tag = env->CP0_EntryHi & ~mask;
1852 VPN = tlb->VPN & ~mask;
1853 /* Check ASID, virtual page number & size */
Chris Dearman55ff3182012-08-03 14:35:52 -07001854 if (unlikely((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag)) {
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001855 /* TLB match */
1856 env->CP0_Index = i;
1857 break;
1858 }
1859 }
1860 if (i == env->tlb->nb_tlb) {
Chris Dearman55ff3182012-08-03 14:35:52 -07001861 /* No match. Discard any shadow entries, if any of them match. */
1862 int index = ((env->CP0_EntryHi>>5)&0x1ff00) | ASID;
1863 index |= (env->CP0_EntryHi>>13)&0x20000;
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001864 env->CP0_Index |= 0x80000000;
1865 }
1866}
1867
David 'Digit' Turner758fa082014-04-03 12:29:21 +02001868void r4k_helper_tlbr(CPUMIPSState *env)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001869{
1870 r4k_tlb_t *tlb;
1871 uint8_t ASID;
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001872
1873 ASID = env->CP0_EntryHi & 0xFF;
Chris Dearman55ff3182012-08-03 14:35:52 -07001874 tlb = &env->tlb->mmu.r4k.tlb[env->CP0_Index % env->tlb->nb_tlb];
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001875
1876 /* If this will change the current ASID, flush qemu's TLB. */
1877 if (ASID != tlb->ASID)
1878 cpu_mips_tlb_flush (env, 1);
1879
Chris Dearman55ff3182012-08-03 14:35:52 -07001880 /*flush all the tlb cache */
1881 cpu_mips_tlb_flush (env, 1);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001882
1883 env->CP0_EntryHi = tlb->VPN | tlb->ASID;
1884 env->CP0_PageMask = tlb->PageMask;
1885 env->CP0_EntryLo0 = tlb->G | (tlb->V0 << 1) | (tlb->D0 << 2) |
1886 (tlb->C0 << 3) | (tlb->PFN[0] >> 6);
1887 env->CP0_EntryLo1 = tlb->G | (tlb->V1 << 1) | (tlb->D1 << 2) |
1888 (tlb->C1 << 3) | (tlb->PFN[1] >> 6);
1889}
1890
David 'Digit' Turner758fa082014-04-03 12:29:21 +02001891void helper_tlbwi(CPUMIPSState *env)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001892{
David 'Digit' Turner758fa082014-04-03 12:29:21 +02001893 env->tlb->helper_tlbwi(env);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001894}
1895
David 'Digit' Turner758fa082014-04-03 12:29:21 +02001896void helper_tlbwr(CPUMIPSState *env)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001897{
David 'Digit' Turner758fa082014-04-03 12:29:21 +02001898 env->tlb->helper_tlbwr(env);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001899}
1900
David 'Digit' Turner758fa082014-04-03 12:29:21 +02001901void helper_tlbp(CPUMIPSState *env)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001902{
David 'Digit' Turner758fa082014-04-03 12:29:21 +02001903 env->tlb->helper_tlbp(env);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001904}
1905
David 'Digit' Turner758fa082014-04-03 12:29:21 +02001906void helper_tlbr(CPUMIPSState *env)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001907{
David 'Digit' Turner758fa082014-04-03 12:29:21 +02001908 env->tlb->helper_tlbr(env);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001909}
1910
1911/* Specials */
David 'Digit' Turner6480c962014-04-03 12:38:04 +02001912target_ulong helper_di(CPUMIPSState *env)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001913{
1914 target_ulong t0 = env->CP0_Status;
1915
1916 env->CP0_Status = t0 & ~(1 << CP0St_IE);
1917 cpu_mips_update_irq(env);
1918
1919 return t0;
1920}
1921
David 'Digit' Turner6480c962014-04-03 12:38:04 +02001922target_ulong helper_ei(CPUMIPSState *env)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001923{
1924 target_ulong t0 = env->CP0_Status;
1925
1926 env->CP0_Status = t0 | (1 << CP0St_IE);
1927 cpu_mips_update_irq(env);
1928
1929 return t0;
1930}
1931
David 'Digit' Turner6480c962014-04-03 12:38:04 +02001932static void debug_pre_eret(CPUMIPSState *env)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001933{
1934 if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
1935 qemu_log("ERET: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
1936 env->active_tc.PC, env->CP0_EPC);
1937 if (env->CP0_Status & (1 << CP0St_ERL))
1938 qemu_log(" ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
1939 if (env->hflags & MIPS_HFLAG_DM)
1940 qemu_log(" DEPC " TARGET_FMT_lx, env->CP0_DEPC);
1941 qemu_log("\n");
1942 }
1943}
1944
David 'Digit' Turner6480c962014-04-03 12:38:04 +02001945static void debug_post_eret(CPUMIPSState *env)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001946{
1947 if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
1948 qemu_log(" => PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
1949 env->active_tc.PC, env->CP0_EPC);
1950 if (env->CP0_Status & (1 << CP0St_ERL))
1951 qemu_log(" ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
1952 if (env->hflags & MIPS_HFLAG_DM)
1953 qemu_log(" DEPC " TARGET_FMT_lx, env->CP0_DEPC);
1954 switch (env->hflags & MIPS_HFLAG_KSU) {
1955 case MIPS_HFLAG_UM: qemu_log(", UM\n"); break;
1956 case MIPS_HFLAG_SM: qemu_log(", SM\n"); break;
1957 case MIPS_HFLAG_KM: qemu_log("\n"); break;
1958 default: cpu_abort(env, "Invalid MMU mode!\n"); break;
1959 }
1960 }
1961}
1962
David 'Digit' Turner6480c962014-04-03 12:38:04 +02001963void helper_eret (CPUMIPSState *env)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001964{
David 'Digit' Turner6480c962014-04-03 12:38:04 +02001965 debug_pre_eret(env);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001966 if (env->CP0_Status & (1 << CP0St_ERL)) {
1967 env->active_tc.PC = env->CP0_ErrorEPC;
1968 env->CP0_Status &= ~(1 << CP0St_ERL);
1969 } else {
1970 env->active_tc.PC = env->CP0_EPC;
1971 env->CP0_Status &= ~(1 << CP0St_EXL);
1972 }
1973 compute_hflags(env);
David 'Digit' Turner6480c962014-04-03 12:38:04 +02001974 debug_post_eret(env);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001975 env->lladdr = 1;
1976}
1977
David 'Digit' Turner6480c962014-04-03 12:38:04 +02001978void helper_deret (CPUMIPSState *env)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001979{
David 'Digit' Turner6480c962014-04-03 12:38:04 +02001980 debug_pre_eret(env);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001981 env->active_tc.PC = env->CP0_DEPC;
1982 env->hflags &= MIPS_HFLAG_DM;
1983 compute_hflags(env);
David 'Digit' Turner6480c962014-04-03 12:38:04 +02001984 debug_post_eret(env);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001985 env->lladdr = 1;
1986}
1987#endif /* !CONFIG_USER_ONLY */
1988
David 'Digit' Turnerd5b76c62014-04-03 12:40:54 +02001989target_ulong helper_rdhwr_cpunum(CPUMIPSState *env)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001990{
1991 if ((env->hflags & MIPS_HFLAG_CP0) ||
1992 (env->CP0_HWREna & (1 << 0)))
1993 return env->CP0_EBase & 0x3ff;
1994 else
David 'Digit' Turner6480c962014-04-03 12:38:04 +02001995 helper_raise_exception(env, EXCP_RI);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08001996
1997 return 0;
1998}
1999
David 'Digit' Turnerd5b76c62014-04-03 12:40:54 +02002000target_ulong helper_rdhwr_synci_step(CPUMIPSState *env)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002001{
2002 if ((env->hflags & MIPS_HFLAG_CP0) ||
2003 (env->CP0_HWREna & (1 << 1)))
2004 return env->SYNCI_Step;
2005 else
David 'Digit' Turner6480c962014-04-03 12:38:04 +02002006 helper_raise_exception(env, EXCP_RI);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002007
2008 return 0;
2009}
2010
David 'Digit' Turnerd5b76c62014-04-03 12:40:54 +02002011target_ulong helper_rdhwr_cc(CPUMIPSState *env)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002012{
2013 if ((env->hflags & MIPS_HFLAG_CP0) ||
2014 (env->CP0_HWREna & (1 << 2)))
2015 return env->CP0_Count;
2016 else
David 'Digit' Turner6480c962014-04-03 12:38:04 +02002017 helper_raise_exception(env, EXCP_RI);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002018
2019 return 0;
2020}
2021
David 'Digit' Turnerd5b76c62014-04-03 12:40:54 +02002022target_ulong helper_rdhwr_ccres(CPUMIPSState *env)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002023{
2024 if ((env->hflags & MIPS_HFLAG_CP0) ||
2025 (env->CP0_HWREna & (1 << 3)))
2026 return env->CCRes;
2027 else
David 'Digit' Turner6480c962014-04-03 12:38:04 +02002028 helper_raise_exception(env, EXCP_RI);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002029
2030 return 0;
2031}
2032
David 'Digit' Turnerd5b76c62014-04-03 12:40:54 +02002033void helper_pmon(CPUMIPSState *env, int function)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002034{
2035 function /= 2;
2036 switch (function) {
2037 case 2: /* TODO: char inbyte(int waitflag); */
2038 if (env->active_tc.gpr[4] == 0)
2039 env->active_tc.gpr[2] = -1;
2040 /* Fall through */
2041 case 11: /* TODO: char inbyte (void); */
2042 env->active_tc.gpr[2] = -1;
2043 break;
2044 case 3:
2045 case 12:
2046 printf("%c", (char)(env->active_tc.gpr[4] & 0xFF));
2047 break;
2048 case 17:
2049 break;
2050 case 158:
2051 {
2052 unsigned char *fmt = (void *)(unsigned long)env->active_tc.gpr[4];
2053 printf("%s", fmt);
2054 }
2055 break;
2056 }
2057}
2058
David 'Digit' Turnerd5b76c62014-04-03 12:40:54 +02002059void helper_wait(CPUMIPSState *env)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002060{
David 'Digit' Turner66576782014-03-24 16:57:57 +01002061 ENV_GET_CPU(env)->halted = 1;
David 'Digit' Turner6480c962014-04-03 12:38:04 +02002062 helper_raise_exception(env, EXCP_HLT);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002063}
2064
2065#if !defined(CONFIG_USER_ONLY)
2066
David 'Digit' Turner6cca40e2014-04-03 17:25:42 +02002067static void do_unaligned_access (CPUMIPSState *env,
David 'Digit' Turner589fe9b2014-04-03 12:23:26 +02002068 target_ulong addr, int is_write,
David 'Digit' Turnereb3bc462014-03-21 11:09:04 +01002069 int is_user, uintptr_t retaddr);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002070
2071#define MMUSUFFIX _mmu
2072#define ALIGNED_ONLY
2073
2074#define SHIFT 0
David 'Digit' Turner852088c2013-12-14 23:04:12 +01002075#include "exec/softmmu_template.h"
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002076
2077#define SHIFT 1
David 'Digit' Turner852088c2013-12-14 23:04:12 +01002078#include "exec/softmmu_template.h"
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002079
2080#define SHIFT 2
David 'Digit' Turner852088c2013-12-14 23:04:12 +01002081#include "exec/softmmu_template.h"
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002082
2083#define SHIFT 3
David 'Digit' Turner852088c2013-12-14 23:04:12 +01002084#include "exec/softmmu_template.h"
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002085
David 'Digit' Turner6cca40e2014-04-03 17:25:42 +02002086static void do_unaligned_access(CPUMIPSState *env, target_ulong addr,
David 'Digit' Turner65b44d52014-04-03 16:02:10 +02002087 int is_write, int is_user, uintptr_t retaddr)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002088{
2089 env->CP0_BadVAddr = addr;
David 'Digit' Turner6480c962014-04-03 12:38:04 +02002090 do_restore_state (env, retaddr);
2091 helper_raise_exception(env, (is_write == 1) ? EXCP_AdES : EXCP_AdEL);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002092}
2093
David 'Digit' Turner65b44d52014-04-03 16:02:10 +02002094void tlb_fill (CPUMIPSState* env, target_ulong addr, int is_write, int mmu_idx,
David 'Digit' Turnereb3bc462014-03-21 11:09:04 +01002095 uintptr_t retaddr)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002096{
2097 TranslationBlock *tb;
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002098 int ret;
2099
David 'Digit' Turner0d8b2352014-03-20 17:13:13 +01002100 ret = cpu_mips_handle_mmu_fault(env, addr, is_write, mmu_idx);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002101 if (ret) {
2102 if (retaddr) {
2103 /* now we have a real cpu fault */
David 'Digit' Turnereb3bc462014-03-21 11:09:04 +01002104 tb = tb_find_pc(retaddr);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002105 if (tb) {
2106 /* the PC is inside the translated code. It means that we have
2107 a virtual CPU fault */
David 'Digit' Turnereb3bc462014-03-21 11:09:04 +01002108 cpu_restore_state(env, retaddr);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002109 }
2110 }
David 'Digit' Turner6480c962014-04-03 12:38:04 +02002111 helper_raise_exception_err(env, env->exception_index, env->error_code);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002112 }
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002113}
2114
David 'Digit' Turner65b44d52014-04-03 16:02:10 +02002115void cpu_unassigned_access(CPUMIPSState* env, hwaddr addr,
David 'Digit' Turner6cf763a2014-03-14 13:25:11 +01002116 int is_write, int is_exec, int unused, int size)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002117{
2118 if (is_exec)
David 'Digit' Turner6480c962014-04-03 12:38:04 +02002119 helper_raise_exception(env, EXCP_IBE);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002120 else
David 'Digit' Turner6480c962014-04-03 12:38:04 +02002121 helper_raise_exception(env, EXCP_DBE);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002122}
Bhanu Chetlapalli325e19d2012-01-31 16:26:04 -08002123/*
David 'Digit' Turnerc0052462014-02-25 18:39:29 +01002124 * The following functions are address translation helper functions
2125 * for fast memory access in QEMU.
Bhanu Chetlapalli325e19d2012-01-31 16:26:04 -08002126 */
David 'Digit' Turner65b44d52014-04-03 16:02:10 +02002127static unsigned long v2p_mmu(CPUMIPSState *env, target_ulong addr, int is_user)
Bhanu Chetlapalli325e19d2012-01-31 16:26:04 -08002128{
2129 int index;
2130 target_ulong tlb_addr;
David 'Digit' Turnereb3bc462014-03-21 11:09:04 +01002131 hwaddr physaddr;
2132 uintptr_t retaddr;
Bhanu Chetlapalli325e19d2012-01-31 16:26:04 -08002133
2134 index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
2135redo:
2136 tlb_addr = env->tlb_table[is_user][index].addr_read;
2137 if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
2138 physaddr = addr + env->tlb_table[is_user][index].addend;
2139 } else {
2140 /* the page is not in the TLB : fill it */
2141 retaddr = GETPC();
David 'Digit' Turner6d1afd32014-03-14 10:51:57 +01002142 tlb_fill(env, addr, 0, is_user, retaddr);
Bhanu Chetlapalli325e19d2012-01-31 16:26:04 -08002143 goto redo;
2144 }
2145 return physaddr;
2146}
2147
David 'Digit' Turnerc0052462014-02-25 18:39:29 +01002148/*
2149 * translation from virtual address of simulated OS
2150 * to the address of simulation host (not the physical
Bhanu Chetlapalli325e19d2012-01-31 16:26:04 -08002151 * address of simulated OS.
2152 */
Duane Sand342a01f2012-06-21 14:30:38 -07002153unsigned long v2p(target_ulong ptr, int is_user)
Bhanu Chetlapalli325e19d2012-01-31 16:26:04 -08002154{
David 'Digit' Turner65b44d52014-04-03 16:02:10 +02002155 CPUMIPSState *env;
Bhanu Chetlapalli325e19d2012-01-31 16:26:04 -08002156 int index;
2157 target_ulong addr;
David 'Digit' Turnereb3bc462014-03-21 11:09:04 +01002158 hwaddr physaddr;
Bhanu Chetlapalli325e19d2012-01-31 16:26:04 -08002159
Bhanu Chetlapalli325e19d2012-01-31 16:26:04 -08002160 env = cpu_single_env;
2161 addr = ptr;
2162 index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
David 'Digit' Turnerc0052462014-02-25 18:39:29 +01002163 if (__builtin_expect(env->tlb_table[is_user][index].addr_read !=
Bhanu Chetlapalli325e19d2012-01-31 16:26:04 -08002164 (addr & TARGET_PAGE_MASK), 0)) {
David 'Digit' Turner65b44d52014-04-03 16:02:10 +02002165 physaddr = v2p_mmu(env, addr, is_user);
Bhanu Chetlapalli325e19d2012-01-31 16:26:04 -08002166 } else {
Duane Sand342a01f2012-06-21 14:30:38 -07002167 physaddr = addr + env->tlb_table[is_user][index].addend;
Bhanu Chetlapalli325e19d2012-01-31 16:26:04 -08002168 }
Bhanu Chetlapalli325e19d2012-01-31 16:26:04 -08002169 return physaddr;
2170}
2171
2172/* copy a string from the simulated virtual space to a buffer in QEMU */
2173void vstrcpy(target_ulong ptr, char *buf, int max)
2174{
2175 char *phys = 0;
David 'Digit' Turnereb3bc462014-03-21 11:09:04 +01002176 target_ulong page = 0;
Bhanu Chetlapalli325e19d2012-01-31 16:26:04 -08002177
2178 if (buf == NULL) return;
2179
2180 while (max) {
2181 if ((ptr & TARGET_PAGE_MASK) != page) {
2182 phys = (char *)v2p(ptr, 0);
2183 page = ptr & TARGET_PAGE_MASK;
2184 }
2185 *buf = *phys;
2186 if (*phys == '\0')
2187 return;
2188 ptr ++;
2189 buf ++;
2190 phys ++;
2191 max --;
2192 }
2193}
2194
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002195#endif /* !CONFIG_USER_ONLY */
2196
2197/* Complex FPU operations which may need stack space. */
2198
2199#define FLOAT_ONE32 make_float32(0x3f8 << 20)
2200#define FLOAT_ONE64 make_float64(0x3ffULL << 52)
2201#define FLOAT_TWO32 make_float32(1 << 30)
2202#define FLOAT_TWO64 make_float64(1ULL << 62)
2203#define FLOAT_QNAN32 0x7fbfffff
2204#define FLOAT_QNAN64 0x7ff7ffffffffffffULL
2205#define FLOAT_SNAN32 0x7fffffff
2206#define FLOAT_SNAN64 0x7fffffffffffffffULL
2207
2208/* convert MIPS rounding mode in FCR31 to IEEE library */
2209static unsigned int ieee_rm[] = {
2210 float_round_nearest_even,
2211 float_round_to_zero,
2212 float_round_up,
2213 float_round_down
2214};
2215
2216#define RESTORE_ROUNDING_MODE \
2217 set_float_rounding_mode(ieee_rm[env->active_fpu.fcr31 & 3], &env->active_fpu.fp_status)
2218
2219#define RESTORE_FLUSH_MODE \
2220 set_flush_to_zero((env->active_fpu.fcr31 & (1 << 24)) != 0, &env->active_fpu.fp_status);
2221
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002222target_ulong helper_cfc1 (CPUMIPSState *env, uint32_t reg)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002223{
2224 target_ulong arg1;
2225
2226 switch (reg) {
2227 case 0:
2228 arg1 = (int32_t)env->active_fpu.fcr0;
2229 break;
2230 case 25:
2231 arg1 = ((env->active_fpu.fcr31 >> 24) & 0xfe) | ((env->active_fpu.fcr31 >> 23) & 0x1);
2232 break;
2233 case 26:
2234 arg1 = env->active_fpu.fcr31 & 0x0003f07c;
2235 break;
2236 case 28:
2237 arg1 = (env->active_fpu.fcr31 & 0x00000f83) | ((env->active_fpu.fcr31 >> 22) & 0x4);
2238 break;
2239 default:
2240 arg1 = (int32_t)env->active_fpu.fcr31;
2241 break;
2242 }
2243
2244 return arg1;
2245}
2246
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002247void helper_ctc1(CPUMIPSState *env, target_ulong arg1, uint32_t reg)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002248{
2249 switch(reg) {
2250 case 25:
2251 if (arg1 & 0xffffff00)
2252 return;
2253 env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0x017fffff) | ((arg1 & 0xfe) << 24) |
2254 ((arg1 & 0x1) << 23);
2255 break;
2256 case 26:
2257 if (arg1 & 0x007c0000)
2258 return;
2259 env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0xfffc0f83) | (arg1 & 0x0003f07c);
2260 break;
2261 case 28:
2262 if (arg1 & 0x007c0000)
2263 return;
2264 env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0xfefff07c) | (arg1 & 0x00000f83) |
2265 ((arg1 & 0x4) << 22);
2266 break;
2267 case 31:
2268 if (arg1 & 0x007c0000)
2269 return;
2270 env->active_fpu.fcr31 = arg1;
2271 break;
2272 default:
2273 return;
2274 }
2275 /* set rounding mode */
2276 RESTORE_ROUNDING_MODE;
2277 /* set flush-to-zero mode */
2278 RESTORE_FLUSH_MODE;
2279 set_float_exception_flags(0, &env->active_fpu.fp_status);
2280 if ((GET_FP_ENABLE(env->active_fpu.fcr31) | 0x20) & GET_FP_CAUSE(env->active_fpu.fcr31))
David 'Digit' Turner6480c962014-04-03 12:38:04 +02002281 helper_raise_exception(env, EXCP_FPE);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002282}
2283
2284static inline char ieee_ex_to_mips(char xcpt)
2285{
2286 return (xcpt & float_flag_inexact) >> 5 |
2287 (xcpt & float_flag_underflow) >> 3 |
2288 (xcpt & float_flag_overflow) >> 1 |
2289 (xcpt & float_flag_divbyzero) << 1 |
2290 (xcpt & float_flag_invalid) << 4;
2291}
2292
2293static inline char mips_ex_to_ieee(char xcpt)
2294{
2295 return (xcpt & FP_INEXACT) << 5 |
2296 (xcpt & FP_UNDERFLOW) << 3 |
2297 (xcpt & FP_OVERFLOW) << 1 |
2298 (xcpt & FP_DIV0) >> 1 |
2299 (xcpt & FP_INVALID) >> 4;
2300}
2301
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002302static inline void update_fcr31(CPUMIPSState *env)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002303{
2304 int tmp = ieee_ex_to_mips(get_float_exception_flags(&env->active_fpu.fp_status));
2305
2306 SET_FP_CAUSE(env->active_fpu.fcr31, tmp);
2307 if (GET_FP_ENABLE(env->active_fpu.fcr31) & tmp)
David 'Digit' Turner6480c962014-04-03 12:38:04 +02002308 helper_raise_exception(env, EXCP_FPE);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002309 else
2310 UPDATE_FP_FLAGS(env->active_fpu.fcr31, tmp);
2311}
2312
2313/* Float support.
2314 Single precition routines have a "s" suffix, double precision a
2315 "d" suffix, 32bit integer "w", 64bit integer "l", paired single "ps",
2316 paired single lower "pl", paired single upper "pu". */
2317
2318/* unary operations, modifying fp status */
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002319uint64_t helper_float_sqrt_d(CPUMIPSState *env, uint64_t fdt0)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002320{
2321 return float64_sqrt(fdt0, &env->active_fpu.fp_status);
2322}
2323
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002324uint32_t helper_float_sqrt_s(CPUMIPSState *env, uint32_t fst0)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002325{
2326 return float32_sqrt(fst0, &env->active_fpu.fp_status);
2327}
2328
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002329uint64_t helper_float_cvtd_s(CPUMIPSState *env, uint32_t fst0)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002330{
2331 uint64_t fdt2;
2332
2333 set_float_exception_flags(0, &env->active_fpu.fp_status);
2334 fdt2 = float32_to_float64(fst0, &env->active_fpu.fp_status);
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002335 update_fcr31(env);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002336 return fdt2;
2337}
2338
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002339uint64_t helper_float_cvtd_w(CPUMIPSState *env, uint32_t wt0)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002340{
2341 uint64_t fdt2;
2342
2343 set_float_exception_flags(0, &env->active_fpu.fp_status);
2344 fdt2 = int32_to_float64(wt0, &env->active_fpu.fp_status);
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002345 update_fcr31(env);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002346 return fdt2;
2347}
2348
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002349uint64_t helper_float_cvtd_l(CPUMIPSState *env, uint64_t dt0)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002350{
2351 uint64_t fdt2;
2352
2353 set_float_exception_flags(0, &env->active_fpu.fp_status);
2354 fdt2 = int64_to_float64(dt0, &env->active_fpu.fp_status);
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002355 update_fcr31(env);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002356 return fdt2;
2357}
2358
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002359uint64_t helper_float_cvtl_d(CPUMIPSState *env, uint64_t fdt0)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002360{
2361 uint64_t dt2;
2362
2363 set_float_exception_flags(0, &env->active_fpu.fp_status);
2364 dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002365 update_fcr31(env);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002366 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2367 dt2 = FLOAT_SNAN64;
2368 return dt2;
2369}
2370
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002371uint64_t helper_float_cvtl_s(CPUMIPSState *env, uint32_t fst0)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002372{
2373 uint64_t dt2;
2374
2375 set_float_exception_flags(0, &env->active_fpu.fp_status);
2376 dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002377 update_fcr31(env);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002378 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2379 dt2 = FLOAT_SNAN64;
2380 return dt2;
2381}
2382
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002383uint64_t helper_float_cvtps_pw(CPUMIPSState *env, uint64_t dt0)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002384{
2385 uint32_t fst2;
2386 uint32_t fsth2;
2387
2388 set_float_exception_flags(0, &env->active_fpu.fp_status);
2389 fst2 = int32_to_float32(dt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
2390 fsth2 = int32_to_float32(dt0 >> 32, &env->active_fpu.fp_status);
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002391 update_fcr31(env);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002392 return ((uint64_t)fsth2 << 32) | fst2;
2393}
2394
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002395uint64_t helper_float_cvtpw_ps(CPUMIPSState *env, uint64_t fdt0)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002396{
2397 uint32_t wt2;
2398 uint32_t wth2;
2399
2400 set_float_exception_flags(0, &env->active_fpu.fp_status);
2401 wt2 = float32_to_int32(fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
2402 wth2 = float32_to_int32(fdt0 >> 32, &env->active_fpu.fp_status);
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002403 update_fcr31(env);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002404 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) {
2405 wt2 = FLOAT_SNAN32;
2406 wth2 = FLOAT_SNAN32;
2407 }
2408 return ((uint64_t)wth2 << 32) | wt2;
2409}
2410
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002411uint32_t helper_float_cvts_d(CPUMIPSState *env, uint64_t fdt0)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002412{
2413 uint32_t fst2;
2414
2415 set_float_exception_flags(0, &env->active_fpu.fp_status);
2416 fst2 = float64_to_float32(fdt0, &env->active_fpu.fp_status);
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002417 update_fcr31(env);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002418 return fst2;
2419}
2420
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002421uint32_t helper_float_cvts_w(CPUMIPSState *env, uint32_t wt0)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002422{
2423 uint32_t fst2;
2424
2425 set_float_exception_flags(0, &env->active_fpu.fp_status);
2426 fst2 = int32_to_float32(wt0, &env->active_fpu.fp_status);
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002427 update_fcr31(env);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002428 return fst2;
2429}
2430
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002431uint32_t helper_float_cvts_l(CPUMIPSState *env, uint64_t dt0)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002432{
2433 uint32_t fst2;
2434
2435 set_float_exception_flags(0, &env->active_fpu.fp_status);
2436 fst2 = int64_to_float32(dt0, &env->active_fpu.fp_status);
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002437 update_fcr31(env);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002438 return fst2;
2439}
2440
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002441uint32_t helper_float_cvts_pl(CPUMIPSState *env, uint32_t wt0)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002442{
2443 uint32_t wt2;
2444
2445 set_float_exception_flags(0, &env->active_fpu.fp_status);
2446 wt2 = wt0;
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002447 update_fcr31(env);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002448 return wt2;
2449}
2450
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002451uint32_t helper_float_cvts_pu(CPUMIPSState *env, uint32_t wth0)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002452{
2453 uint32_t wt2;
2454
2455 set_float_exception_flags(0, &env->active_fpu.fp_status);
2456 wt2 = wth0;
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002457 update_fcr31(env);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002458 return wt2;
2459}
2460
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002461uint32_t helper_float_cvtw_s(CPUMIPSState *env, uint32_t fst0)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002462{
2463 uint32_t wt2;
2464
2465 set_float_exception_flags(0, &env->active_fpu.fp_status);
2466 wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002467 update_fcr31(env);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002468 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2469 wt2 = FLOAT_SNAN32;
2470 return wt2;
2471}
2472
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002473uint32_t helper_float_cvtw_d(CPUMIPSState *env, uint64_t fdt0)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002474{
2475 uint32_t wt2;
2476
2477 set_float_exception_flags(0, &env->active_fpu.fp_status);
2478 wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002479 update_fcr31(env);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002480 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2481 wt2 = FLOAT_SNAN32;
2482 return wt2;
2483}
2484
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002485uint64_t helper_float_roundl_d(CPUMIPSState *env, uint64_t fdt0)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002486{
2487 uint64_t dt2;
2488
Bhanu Chetlapalli5b954e62012-01-31 16:31:29 -08002489 set_float_exception_flags(0, &env->active_fpu.fp_status);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002490 set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2491 dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
2492 RESTORE_ROUNDING_MODE;
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002493 update_fcr31(env);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002494 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2495 dt2 = FLOAT_SNAN64;
2496 return dt2;
2497}
2498
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002499uint64_t helper_float_roundl_s(CPUMIPSState *env, uint32_t fst0)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002500{
2501 uint64_t dt2;
2502
Bhanu Chetlapalli5b954e62012-01-31 16:31:29 -08002503 set_float_exception_flags(0, &env->active_fpu.fp_status);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002504 set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2505 dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
2506 RESTORE_ROUNDING_MODE;
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002507 update_fcr31(env);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002508 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2509 dt2 = FLOAT_SNAN64;
2510 return dt2;
2511}
2512
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002513uint32_t helper_float_roundw_d(CPUMIPSState *env, uint64_t fdt0)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002514{
2515 uint32_t wt2;
2516
Bhanu Chetlapalli5b954e62012-01-31 16:31:29 -08002517 set_float_exception_flags(0, &env->active_fpu.fp_status);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002518 set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2519 wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
2520 RESTORE_ROUNDING_MODE;
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002521 update_fcr31(env);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002522 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2523 wt2 = FLOAT_SNAN32;
2524 return wt2;
2525}
2526
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002527uint32_t helper_float_roundw_s(CPUMIPSState *env, uint32_t fst0)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002528{
2529 uint32_t wt2;
2530
Bhanu Chetlapalli5b954e62012-01-31 16:31:29 -08002531 set_float_exception_flags(0, &env->active_fpu.fp_status);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002532 set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2533 wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
2534 RESTORE_ROUNDING_MODE;
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002535 update_fcr31(env);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002536 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2537 wt2 = FLOAT_SNAN32;
2538 return wt2;
2539}
2540
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002541uint64_t helper_float_truncl_d(CPUMIPSState *env, uint64_t fdt0)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002542{
2543 uint64_t dt2;
2544
Bhanu Chetlapalli5b954e62012-01-31 16:31:29 -08002545 set_float_exception_flags(0, &env->active_fpu.fp_status);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002546 dt2 = float64_to_int64_round_to_zero(fdt0, &env->active_fpu.fp_status);
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002547 update_fcr31(env);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002548 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2549 dt2 = FLOAT_SNAN64;
2550 return dt2;
2551}
2552
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002553uint64_t helper_float_truncl_s(CPUMIPSState *env, uint32_t fst0)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002554{
2555 uint64_t dt2;
2556
Bhanu Chetlapalli5b954e62012-01-31 16:31:29 -08002557 set_float_exception_flags(0, &env->active_fpu.fp_status);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002558 dt2 = float32_to_int64_round_to_zero(fst0, &env->active_fpu.fp_status);
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002559 update_fcr31(env);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002560 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2561 dt2 = FLOAT_SNAN64;
2562 return dt2;
2563}
2564
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002565uint32_t helper_float_truncw_d(CPUMIPSState *env, uint64_t fdt0)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002566{
2567 uint32_t wt2;
2568
Bhanu Chetlapalli5b954e62012-01-31 16:31:29 -08002569 set_float_exception_flags(0, &env->active_fpu.fp_status);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002570 wt2 = float64_to_int32_round_to_zero(fdt0, &env->active_fpu.fp_status);
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002571 update_fcr31(env);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002572 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2573 wt2 = FLOAT_SNAN32;
2574 return wt2;
2575}
2576
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002577uint32_t helper_float_truncw_s(CPUMIPSState *env, uint32_t fst0)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002578{
2579 uint32_t wt2;
2580
Bhanu Chetlapalli5b954e62012-01-31 16:31:29 -08002581 set_float_exception_flags(0, &env->active_fpu.fp_status);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002582 wt2 = float32_to_int32_round_to_zero(fst0, &env->active_fpu.fp_status);
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002583 update_fcr31(env);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002584 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2585 wt2 = FLOAT_SNAN32;
2586 return wt2;
2587}
2588
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002589uint64_t helper_float_ceill_d(CPUMIPSState *env, uint64_t fdt0)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002590{
2591 uint64_t dt2;
2592
Bhanu Chetlapalli5b954e62012-01-31 16:31:29 -08002593 set_float_exception_flags(0, &env->active_fpu.fp_status);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002594 set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
2595 dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
2596 RESTORE_ROUNDING_MODE;
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002597 update_fcr31(env);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002598 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2599 dt2 = FLOAT_SNAN64;
2600 return dt2;
2601}
2602
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002603uint64_t helper_float_ceill_s(CPUMIPSState *env, uint32_t fst0)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002604{
2605 uint64_t dt2;
2606
Bhanu Chetlapalli5b954e62012-01-31 16:31:29 -08002607 set_float_exception_flags(0, &env->active_fpu.fp_status);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002608 set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
2609 dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
2610 RESTORE_ROUNDING_MODE;
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002611 update_fcr31(env);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002612 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2613 dt2 = FLOAT_SNAN64;
2614 return dt2;
2615}
2616
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002617uint32_t helper_float_ceilw_d(CPUMIPSState *env, uint64_t fdt0)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002618{
2619 uint32_t wt2;
2620
Bhanu Chetlapalli5b954e62012-01-31 16:31:29 -08002621 set_float_exception_flags(0, &env->active_fpu.fp_status);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002622 set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
2623 wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
2624 RESTORE_ROUNDING_MODE;
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002625 update_fcr31(env);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002626 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2627 wt2 = FLOAT_SNAN32;
2628 return wt2;
2629}
2630
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002631uint32_t helper_float_ceilw_s(CPUMIPSState *env, uint32_t fst0)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002632{
2633 uint32_t wt2;
2634
Bhanu Chetlapalli5b954e62012-01-31 16:31:29 -08002635 set_float_exception_flags(0, &env->active_fpu.fp_status);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002636 set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
2637 wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
2638 RESTORE_ROUNDING_MODE;
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002639 update_fcr31(env);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002640 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2641 wt2 = FLOAT_SNAN32;
2642 return wt2;
2643}
2644
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002645uint64_t helper_float_floorl_d(CPUMIPSState *env, uint64_t fdt0)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002646{
2647 uint64_t dt2;
2648
Bhanu Chetlapalli5b954e62012-01-31 16:31:29 -08002649 set_float_exception_flags(0, &env->active_fpu.fp_status);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002650 set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
2651 dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
2652 RESTORE_ROUNDING_MODE;
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002653 update_fcr31(env);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002654 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2655 dt2 = FLOAT_SNAN64;
2656 return dt2;
2657}
2658
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002659uint64_t helper_float_floorl_s(CPUMIPSState *env, uint32_t fst0)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002660{
2661 uint64_t dt2;
2662
Bhanu Chetlapalli5b954e62012-01-31 16:31:29 -08002663 set_float_exception_flags(0, &env->active_fpu.fp_status);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002664 set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
2665 dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
2666 RESTORE_ROUNDING_MODE;
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002667 update_fcr31(env);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002668 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2669 dt2 = FLOAT_SNAN64;
2670 return dt2;
2671}
2672
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002673uint32_t helper_float_floorw_d(CPUMIPSState *env, uint64_t fdt0)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002674{
2675 uint32_t wt2;
2676
Bhanu Chetlapalli5b954e62012-01-31 16:31:29 -08002677 set_float_exception_flags(0, &env->active_fpu.fp_status);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002678 set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
2679 wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
2680 RESTORE_ROUNDING_MODE;
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002681 update_fcr31(env);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002682 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2683 wt2 = FLOAT_SNAN32;
2684 return wt2;
2685}
2686
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002687uint32_t helper_float_floorw_s(CPUMIPSState *env, uint32_t fst0)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002688{
2689 uint32_t wt2;
2690
Bhanu Chetlapalli5b954e62012-01-31 16:31:29 -08002691 set_float_exception_flags(0, &env->active_fpu.fp_status);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002692 set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
2693 wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
2694 RESTORE_ROUNDING_MODE;
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002695 update_fcr31(env);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002696 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2697 wt2 = FLOAT_SNAN32;
2698 return wt2;
2699}
2700
2701/* unary operations, not modifying fp status */
2702#define FLOAT_UNOP(name) \
2703uint64_t helper_float_ ## name ## _d(uint64_t fdt0) \
2704{ \
2705 return float64_ ## name(fdt0); \
2706} \
2707uint32_t helper_float_ ## name ## _s(uint32_t fst0) \
2708{ \
2709 return float32_ ## name(fst0); \
2710} \
2711uint64_t helper_float_ ## name ## _ps(uint64_t fdt0) \
2712{ \
2713 uint32_t wt0; \
2714 uint32_t wth0; \
2715 \
2716 wt0 = float32_ ## name(fdt0 & 0XFFFFFFFF); \
2717 wth0 = float32_ ## name(fdt0 >> 32); \
2718 return ((uint64_t)wth0 << 32) | wt0; \
2719}
2720FLOAT_UNOP(abs)
2721FLOAT_UNOP(chs)
2722#undef FLOAT_UNOP
2723
2724/* MIPS specific unary operations */
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002725uint64_t helper_float_recip_d(CPUMIPSState *env, uint64_t fdt0)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002726{
2727 uint64_t fdt2;
2728
2729 set_float_exception_flags(0, &env->active_fpu.fp_status);
2730 fdt2 = float64_div(FLOAT_ONE64, fdt0, &env->active_fpu.fp_status);
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002731 update_fcr31(env);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002732 return fdt2;
2733}
2734
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002735uint32_t helper_float_recip_s(CPUMIPSState *env, uint32_t fst0)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002736{
2737 uint32_t fst2;
2738
2739 set_float_exception_flags(0, &env->active_fpu.fp_status);
2740 fst2 = float32_div(FLOAT_ONE32, fst0, &env->active_fpu.fp_status);
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002741 update_fcr31(env);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002742 return fst2;
2743}
2744
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002745uint64_t helper_float_rsqrt_d(CPUMIPSState *env, uint64_t fdt0)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002746{
2747 uint64_t fdt2;
2748
2749 set_float_exception_flags(0, &env->active_fpu.fp_status);
2750 fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
2751 fdt2 = float64_div(FLOAT_ONE64, fdt2, &env->active_fpu.fp_status);
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002752 update_fcr31(env);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002753 return fdt2;
2754}
2755
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002756uint32_t helper_float_rsqrt_s(CPUMIPSState *env, uint32_t fst0)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002757{
2758 uint32_t fst2;
2759
2760 set_float_exception_flags(0, &env->active_fpu.fp_status);
2761 fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status);
2762 fst2 = float32_div(FLOAT_ONE32, fst2, &env->active_fpu.fp_status);
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002763 update_fcr31(env);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002764 return fst2;
2765}
2766
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002767uint64_t helper_float_recip1_d(CPUMIPSState *env, uint64_t fdt0)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002768{
2769 uint64_t fdt2;
2770
2771 set_float_exception_flags(0, &env->active_fpu.fp_status);
2772 fdt2 = float64_div(FLOAT_ONE64, fdt0, &env->active_fpu.fp_status);
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002773 update_fcr31(env);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002774 return fdt2;
2775}
2776
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002777uint32_t helper_float_recip1_s(CPUMIPSState *env, uint32_t fst0)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002778{
2779 uint32_t fst2;
2780
2781 set_float_exception_flags(0, &env->active_fpu.fp_status);
2782 fst2 = float32_div(FLOAT_ONE32, fst0, &env->active_fpu.fp_status);
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002783 update_fcr31(env);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002784 return fst2;
2785}
2786
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002787uint64_t helper_float_recip1_ps(CPUMIPSState *env, uint64_t fdt0)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002788{
2789 uint32_t fst2;
2790 uint32_t fsth2;
2791
2792 set_float_exception_flags(0, &env->active_fpu.fp_status);
2793 fst2 = float32_div(FLOAT_ONE32, fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
2794 fsth2 = float32_div(FLOAT_ONE32, fdt0 >> 32, &env->active_fpu.fp_status);
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002795 update_fcr31(env);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002796 return ((uint64_t)fsth2 << 32) | fst2;
2797}
2798
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002799uint64_t helper_float_rsqrt1_d(CPUMIPSState *env, uint64_t fdt0)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002800{
2801 uint64_t fdt2;
2802
2803 set_float_exception_flags(0, &env->active_fpu.fp_status);
2804 fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
2805 fdt2 = float64_div(FLOAT_ONE64, fdt2, &env->active_fpu.fp_status);
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002806 update_fcr31(env);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002807 return fdt2;
2808}
2809
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002810uint32_t helper_float_rsqrt1_s(CPUMIPSState *env, uint32_t fst0)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002811{
2812 uint32_t fst2;
2813
2814 set_float_exception_flags(0, &env->active_fpu.fp_status);
2815 fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status);
2816 fst2 = float32_div(FLOAT_ONE32, fst2, &env->active_fpu.fp_status);
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002817 update_fcr31(env);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002818 return fst2;
2819}
2820
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002821uint64_t helper_float_rsqrt1_ps(CPUMIPSState *env, uint64_t fdt0)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002822{
2823 uint32_t fst2;
2824 uint32_t fsth2;
2825
2826 set_float_exception_flags(0, &env->active_fpu.fp_status);
2827 fst2 = float32_sqrt(fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
2828 fsth2 = float32_sqrt(fdt0 >> 32, &env->active_fpu.fp_status);
2829 fst2 = float32_div(FLOAT_ONE32, fst2, &env->active_fpu.fp_status);
2830 fsth2 = float32_div(FLOAT_ONE32, fsth2, &env->active_fpu.fp_status);
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002831 update_fcr31(env);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002832 return ((uint64_t)fsth2 << 32) | fst2;
2833}
2834
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002835#define FLOAT_OP(name, p) void helper_float_##name##_##p(CPUMIPSState *env)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002836
2837/* binary operations */
2838#define FLOAT_BINOP(name) \
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002839uint64_t helper_float_ ## name ## _d(CPUMIPSState *env, \
2840 uint64_t fdt0, uint64_t fdt1) \
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002841{ \
2842 uint64_t dt2; \
2843 \
2844 set_float_exception_flags(0, &env->active_fpu.fp_status); \
2845 dt2 = float64_ ## name (fdt0, fdt1, &env->active_fpu.fp_status); \
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002846 update_fcr31(env); \
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002847 if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_INVALID) \
2848 dt2 = FLOAT_QNAN64; \
2849 return dt2; \
2850} \
2851 \
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002852uint32_t helper_float_ ## name ## _s(CPUMIPSState *env, \
2853 uint32_t fst0, uint32_t fst1) \
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002854{ \
2855 uint32_t wt2; \
2856 \
2857 set_float_exception_flags(0, &env->active_fpu.fp_status); \
2858 wt2 = float32_ ## name (fst0, fst1, &env->active_fpu.fp_status); \
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002859 update_fcr31(env); \
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002860 if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_INVALID) \
2861 wt2 = FLOAT_QNAN32; \
2862 return wt2; \
2863} \
2864 \
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002865uint64_t helper_float_ ## name ## _ps(CPUMIPSState *env, \
2866 uint64_t fdt0, \
2867 uint64_t fdt1) \
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002868{ \
2869 uint32_t fst0 = fdt0 & 0XFFFFFFFF; \
2870 uint32_t fsth0 = fdt0 >> 32; \
2871 uint32_t fst1 = fdt1 & 0XFFFFFFFF; \
2872 uint32_t fsth1 = fdt1 >> 32; \
2873 uint32_t wt2; \
2874 uint32_t wth2; \
2875 \
2876 set_float_exception_flags(0, &env->active_fpu.fp_status); \
2877 wt2 = float32_ ## name (fst0, fst1, &env->active_fpu.fp_status); \
2878 wth2 = float32_ ## name (fsth0, fsth1, &env->active_fpu.fp_status); \
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002879 update_fcr31(env); \
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002880 if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_INVALID) { \
2881 wt2 = FLOAT_QNAN32; \
2882 wth2 = FLOAT_QNAN32; \
2883 } \
2884 return ((uint64_t)wth2 << 32) | wt2; \
2885}
2886
2887FLOAT_BINOP(add)
2888FLOAT_BINOP(sub)
2889FLOAT_BINOP(mul)
2890FLOAT_BINOP(div)
2891#undef FLOAT_BINOP
2892
2893/* ternary operations */
2894#define FLOAT_TERNOP(name1, name2) \
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002895uint64_t helper_float_ ## name1 ## name2 ## _d(CPUMIPSState *env, \
2896 uint64_t fdt0, uint64_t fdt1, \
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002897 uint64_t fdt2) \
2898{ \
2899 fdt0 = float64_ ## name1 (fdt0, fdt1, &env->active_fpu.fp_status); \
2900 return float64_ ## name2 (fdt0, fdt2, &env->active_fpu.fp_status); \
2901} \
2902 \
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002903uint32_t helper_float_ ## name1 ## name2 ## _s(CPUMIPSState *env, \
2904 uint32_t fst0, uint32_t fst1, \
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002905 uint32_t fst2) \
2906{ \
2907 fst0 = float32_ ## name1 (fst0, fst1, &env->active_fpu.fp_status); \
2908 return float32_ ## name2 (fst0, fst2, &env->active_fpu.fp_status); \
2909} \
2910 \
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002911uint64_t helper_float_ ## name1 ## name2 ## _ps(CPUMIPSState *env, \
2912 uint64_t fdt0, uint64_t fdt1, \
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002913 uint64_t fdt2) \
2914{ \
2915 uint32_t fst0 = fdt0 & 0XFFFFFFFF; \
2916 uint32_t fsth0 = fdt0 >> 32; \
2917 uint32_t fst1 = fdt1 & 0XFFFFFFFF; \
2918 uint32_t fsth1 = fdt1 >> 32; \
2919 uint32_t fst2 = fdt2 & 0XFFFFFFFF; \
2920 uint32_t fsth2 = fdt2 >> 32; \
2921 \
2922 fst0 = float32_ ## name1 (fst0, fst1, &env->active_fpu.fp_status); \
2923 fsth0 = float32_ ## name1 (fsth0, fsth1, &env->active_fpu.fp_status); \
2924 fst2 = float32_ ## name2 (fst0, fst2, &env->active_fpu.fp_status); \
2925 fsth2 = float32_ ## name2 (fsth0, fsth2, &env->active_fpu.fp_status); \
2926 return ((uint64_t)fsth2 << 32) | fst2; \
2927}
2928
2929FLOAT_TERNOP(mul, add)
2930FLOAT_TERNOP(mul, sub)
2931#undef FLOAT_TERNOP
2932
2933/* negated ternary operations */
2934#define FLOAT_NTERNOP(name1, name2) \
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002935uint64_t helper_float_n ## name1 ## name2 ## _d(CPUMIPSState *env, \
2936 uint64_t fdt0, uint64_t fdt1, \
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002937 uint64_t fdt2) \
2938{ \
2939 fdt0 = float64_ ## name1 (fdt0, fdt1, &env->active_fpu.fp_status); \
2940 fdt2 = float64_ ## name2 (fdt0, fdt2, &env->active_fpu.fp_status); \
2941 return float64_chs(fdt2); \
2942} \
2943 \
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002944uint32_t helper_float_n ## name1 ## name2 ## _s(CPUMIPSState *env, \
2945 uint32_t fst0, uint32_t fst1, \
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002946 uint32_t fst2) \
2947{ \
2948 fst0 = float32_ ## name1 (fst0, fst1, &env->active_fpu.fp_status); \
2949 fst2 = float32_ ## name2 (fst0, fst2, &env->active_fpu.fp_status); \
2950 return float32_chs(fst2); \
2951} \
2952 \
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002953uint64_t helper_float_n ## name1 ## name2 ## _ps(CPUMIPSState *env, \
2954 uint64_t fdt0, uint64_t fdt1,\
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002955 uint64_t fdt2) \
2956{ \
2957 uint32_t fst0 = fdt0 & 0XFFFFFFFF; \
2958 uint32_t fsth0 = fdt0 >> 32; \
2959 uint32_t fst1 = fdt1 & 0XFFFFFFFF; \
2960 uint32_t fsth1 = fdt1 >> 32; \
2961 uint32_t fst2 = fdt2 & 0XFFFFFFFF; \
2962 uint32_t fsth2 = fdt2 >> 32; \
2963 \
2964 fst0 = float32_ ## name1 (fst0, fst1, &env->active_fpu.fp_status); \
2965 fsth0 = float32_ ## name1 (fsth0, fsth1, &env->active_fpu.fp_status); \
2966 fst2 = float32_ ## name2 (fst0, fst2, &env->active_fpu.fp_status); \
2967 fsth2 = float32_ ## name2 (fsth0, fsth2, &env->active_fpu.fp_status); \
2968 fst2 = float32_chs(fst2); \
2969 fsth2 = float32_chs(fsth2); \
2970 return ((uint64_t)fsth2 << 32) | fst2; \
2971}
2972
2973FLOAT_NTERNOP(mul, add)
2974FLOAT_NTERNOP(mul, sub)
2975#undef FLOAT_NTERNOP
2976
2977/* MIPS specific binary operations */
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002978uint64_t helper_float_recip2_d(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002979{
2980 set_float_exception_flags(0, &env->active_fpu.fp_status);
2981 fdt2 = float64_mul(fdt0, fdt2, &env->active_fpu.fp_status);
2982 fdt2 = float64_chs(float64_sub(fdt2, FLOAT_ONE64, &env->active_fpu.fp_status));
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002983 update_fcr31(env);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002984 return fdt2;
2985}
2986
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002987uint32_t helper_float_recip2_s(CPUMIPSState *env, uint32_t fst0, uint32_t fst2)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002988{
2989 set_float_exception_flags(0, &env->active_fpu.fp_status);
2990 fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
2991 fst2 = float32_chs(float32_sub(fst2, FLOAT_ONE32, &env->active_fpu.fp_status));
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002992 update_fcr31(env);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002993 return fst2;
2994}
2995
David 'Digit' Turner87350d12014-04-03 15:44:48 +02002996uint64_t helper_float_recip2_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08002997{
2998 uint32_t fst0 = fdt0 & 0XFFFFFFFF;
2999 uint32_t fsth0 = fdt0 >> 32;
3000 uint32_t fst2 = fdt2 & 0XFFFFFFFF;
3001 uint32_t fsth2 = fdt2 >> 32;
3002
3003 set_float_exception_flags(0, &env->active_fpu.fp_status);
3004 fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
3005 fsth2 = float32_mul(fsth0, fsth2, &env->active_fpu.fp_status);
3006 fst2 = float32_chs(float32_sub(fst2, FLOAT_ONE32, &env->active_fpu.fp_status));
3007 fsth2 = float32_chs(float32_sub(fsth2, FLOAT_ONE32, &env->active_fpu.fp_status));
David 'Digit' Turner87350d12014-04-03 15:44:48 +02003008 update_fcr31(env);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08003009 return ((uint64_t)fsth2 << 32) | fst2;
3010}
3011
David 'Digit' Turner87350d12014-04-03 15:44:48 +02003012uint64_t helper_float_rsqrt2_d(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08003013{
3014 set_float_exception_flags(0, &env->active_fpu.fp_status);
3015 fdt2 = float64_mul(fdt0, fdt2, &env->active_fpu.fp_status);
3016 fdt2 = float64_sub(fdt2, FLOAT_ONE64, &env->active_fpu.fp_status);
3017 fdt2 = float64_chs(float64_div(fdt2, FLOAT_TWO64, &env->active_fpu.fp_status));
David 'Digit' Turner87350d12014-04-03 15:44:48 +02003018 update_fcr31(env);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08003019 return fdt2;
3020}
3021
David 'Digit' Turner87350d12014-04-03 15:44:48 +02003022uint32_t helper_float_rsqrt2_s(CPUMIPSState *env, uint32_t fst0, uint32_t fst2)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08003023{
3024 set_float_exception_flags(0, &env->active_fpu.fp_status);
3025 fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
3026 fst2 = float32_sub(fst2, FLOAT_ONE32, &env->active_fpu.fp_status);
3027 fst2 = float32_chs(float32_div(fst2, FLOAT_TWO32, &env->active_fpu.fp_status));
David 'Digit' Turner87350d12014-04-03 15:44:48 +02003028 update_fcr31(env);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08003029 return fst2;
3030}
3031
David 'Digit' Turner87350d12014-04-03 15:44:48 +02003032uint64_t helper_float_rsqrt2_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08003033{
3034 uint32_t fst0 = fdt0 & 0XFFFFFFFF;
3035 uint32_t fsth0 = fdt0 >> 32;
3036 uint32_t fst2 = fdt2 & 0XFFFFFFFF;
3037 uint32_t fsth2 = fdt2 >> 32;
3038
3039 set_float_exception_flags(0, &env->active_fpu.fp_status);
3040 fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
3041 fsth2 = float32_mul(fsth0, fsth2, &env->active_fpu.fp_status);
3042 fst2 = float32_sub(fst2, FLOAT_ONE32, &env->active_fpu.fp_status);
3043 fsth2 = float32_sub(fsth2, FLOAT_ONE32, &env->active_fpu.fp_status);
3044 fst2 = float32_chs(float32_div(fst2, FLOAT_TWO32, &env->active_fpu.fp_status));
3045 fsth2 = float32_chs(float32_div(fsth2, FLOAT_TWO32, &env->active_fpu.fp_status));
David 'Digit' Turner87350d12014-04-03 15:44:48 +02003046 update_fcr31(env);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08003047 return ((uint64_t)fsth2 << 32) | fst2;
3048}
3049
David 'Digit' Turner87350d12014-04-03 15:44:48 +02003050uint64_t helper_float_addr_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt1)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08003051{
3052 uint32_t fst0 = fdt0 & 0XFFFFFFFF;
3053 uint32_t fsth0 = fdt0 >> 32;
3054 uint32_t fst1 = fdt1 & 0XFFFFFFFF;
3055 uint32_t fsth1 = fdt1 >> 32;
3056 uint32_t fst2;
3057 uint32_t fsth2;
3058
3059 set_float_exception_flags(0, &env->active_fpu.fp_status);
3060 fst2 = float32_add (fst0, fsth0, &env->active_fpu.fp_status);
3061 fsth2 = float32_add (fst1, fsth1, &env->active_fpu.fp_status);
David 'Digit' Turner87350d12014-04-03 15:44:48 +02003062 update_fcr31(env);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08003063 return ((uint64_t)fsth2 << 32) | fst2;
3064}
3065
David 'Digit' Turner87350d12014-04-03 15:44:48 +02003066uint64_t helper_float_mulr_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt1)
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08003067{
3068 uint32_t fst0 = fdt0 & 0XFFFFFFFF;
3069 uint32_t fsth0 = fdt0 >> 32;
3070 uint32_t fst1 = fdt1 & 0XFFFFFFFF;
3071 uint32_t fsth1 = fdt1 >> 32;
3072 uint32_t fst2;
3073 uint32_t fsth2;
3074
3075 set_float_exception_flags(0, &env->active_fpu.fp_status);
3076 fst2 = float32_mul (fst0, fsth0, &env->active_fpu.fp_status);
3077 fsth2 = float32_mul (fst1, fsth1, &env->active_fpu.fp_status);
David 'Digit' Turner87350d12014-04-03 15:44:48 +02003078 update_fcr31(env);
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08003079 return ((uint64_t)fsth2 << 32) | fst2;
3080}
3081
3082/* compare operations */
3083#define FOP_COND_D(op, cond) \
David 'Digit' Turner87350d12014-04-03 15:44:48 +02003084void helper_cmp_d_ ## op(CPUMIPSState *env, uint64_t fdt0, \
3085 uint64_t fdt1, int cc) \
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08003086{ \
3087 int c = cond; \
David 'Digit' Turner87350d12014-04-03 15:44:48 +02003088 update_fcr31(env); \
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08003089 if (c) \
3090 SET_FP_COND(cc, env->active_fpu); \
3091 else \
3092 CLEAR_FP_COND(cc, env->active_fpu); \
3093} \
David 'Digit' Turner87350d12014-04-03 15:44:48 +02003094void helper_cmpabs_d_ ## op(CPUMIPSState *env, uint64_t fdt0, \
3095 uint64_t fdt1, int cc) \
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08003096{ \
3097 int c; \
3098 fdt0 = float64_abs(fdt0); \
3099 fdt1 = float64_abs(fdt1); \
3100 c = cond; \
David 'Digit' Turner87350d12014-04-03 15:44:48 +02003101 update_fcr31(env); \
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08003102 if (c) \
3103 SET_FP_COND(cc, env->active_fpu); \
3104 else \
3105 CLEAR_FP_COND(cc, env->active_fpu); \
3106}
3107
3108static int float64_is_unordered(int sig, float64 a, float64 b STATUS_PARAM)
3109{
3110 if (float64_is_signaling_nan(a) ||
3111 float64_is_signaling_nan(b) ||
Bhanu Chetlapalli325e19d2012-01-31 16:26:04 -08003112 (sig && (float64_is_any_nan(a) || float64_is_any_nan(b)))) {
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08003113 float_raise(float_flag_invalid, status);
3114 return 1;
Bhanu Chetlapalli325e19d2012-01-31 16:26:04 -08003115 } else if (float64_is_any_nan(a) || float64_is_any_nan(b)) {
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08003116 return 1;
3117 } else {
3118 return 0;
3119 }
3120}
3121
3122/* NOTE: the comma operator will make "cond" to eval to false,
3123 * but float*_is_unordered() is still called. */
3124FOP_COND_D(f, (float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status), 0))
3125FOP_COND_D(un, float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status))
3126FOP_COND_D(eq, !float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status) && float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
3127FOP_COND_D(ueq, float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status) || float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
3128FOP_COND_D(olt, !float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status) && float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
3129FOP_COND_D(ult, float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status) || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
3130FOP_COND_D(ole, !float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status) && float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
3131FOP_COND_D(ule, float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status) || float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
3132/* NOTE: the comma operator will make "cond" to eval to false,
3133 * but float*_is_unordered() is still called. */
3134FOP_COND_D(sf, (float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status), 0))
3135FOP_COND_D(ngle,float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status))
3136FOP_COND_D(seq, !float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status) && float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
3137FOP_COND_D(ngl, float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status) || float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
3138FOP_COND_D(lt, !float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status) && float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
3139FOP_COND_D(nge, float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status) || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
3140FOP_COND_D(le, !float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status) && float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
3141FOP_COND_D(ngt, float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status) || float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
3142
3143#define FOP_COND_S(op, cond) \
David 'Digit' Turner87350d12014-04-03 15:44:48 +02003144void helper_cmp_s_ ## op(CPUMIPSState *env, uint32_t fst0, \
3145 uint32_t fst1, int cc) \
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08003146{ \
3147 int c = cond; \
David 'Digit' Turner87350d12014-04-03 15:44:48 +02003148 update_fcr31(env); \
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08003149 if (c) \
3150 SET_FP_COND(cc, env->active_fpu); \
3151 else \
3152 CLEAR_FP_COND(cc, env->active_fpu); \
3153} \
David 'Digit' Turner87350d12014-04-03 15:44:48 +02003154void helper_cmpabs_s_ ## op(CPUMIPSState *env, uint32_t fst0, \
3155 uint32_t fst1, int cc) \
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08003156{ \
3157 int c; \
3158 fst0 = float32_abs(fst0); \
3159 fst1 = float32_abs(fst1); \
3160 c = cond; \
David 'Digit' Turner87350d12014-04-03 15:44:48 +02003161 update_fcr31(env); \
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08003162 if (c) \
3163 SET_FP_COND(cc, env->active_fpu); \
3164 else \
3165 CLEAR_FP_COND(cc, env->active_fpu); \
3166}
3167
3168static flag float32_is_unordered(int sig, float32 a, float32 b STATUS_PARAM)
3169{
3170 if (float32_is_signaling_nan(a) ||
3171 float32_is_signaling_nan(b) ||
Bhanu Chetlapalli325e19d2012-01-31 16:26:04 -08003172 (sig && (float32_is_any_nan(a) || float32_is_any_nan(b)))) {
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08003173 float_raise(float_flag_invalid, status);
3174 return 1;
Bhanu Chetlapalli325e19d2012-01-31 16:26:04 -08003175 } else if (float32_is_any_nan(a) || float32_is_any_nan(b)) {
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08003176 return 1;
3177 } else {
3178 return 0;
3179 }
3180}
3181
3182/* NOTE: the comma operator will make "cond" to eval to false,
3183 * but float*_is_unordered() is still called. */
3184FOP_COND_S(f, (float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status), 0))
3185FOP_COND_S(un, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status))
3186FOP_COND_S(eq, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) && float32_eq(fst0, fst1, &env->active_fpu.fp_status))
3187FOP_COND_S(ueq, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) || float32_eq(fst0, fst1, &env->active_fpu.fp_status))
3188FOP_COND_S(olt, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) && float32_lt(fst0, fst1, &env->active_fpu.fp_status))
3189FOP_COND_S(ult, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) || float32_lt(fst0, fst1, &env->active_fpu.fp_status))
3190FOP_COND_S(ole, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) && float32_le(fst0, fst1, &env->active_fpu.fp_status))
3191FOP_COND_S(ule, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) || float32_le(fst0, fst1, &env->active_fpu.fp_status))
3192/* NOTE: the comma operator will make "cond" to eval to false,
3193 * but float*_is_unordered() is still called. */
3194FOP_COND_S(sf, (float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status), 0))
3195FOP_COND_S(ngle,float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status))
3196FOP_COND_S(seq, !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) && float32_eq(fst0, fst1, &env->active_fpu.fp_status))
3197FOP_COND_S(ngl, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) || float32_eq(fst0, fst1, &env->active_fpu.fp_status))
3198FOP_COND_S(lt, !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) && float32_lt(fst0, fst1, &env->active_fpu.fp_status))
3199FOP_COND_S(nge, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) || float32_lt(fst0, fst1, &env->active_fpu.fp_status))
3200FOP_COND_S(le, !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) && float32_le(fst0, fst1, &env->active_fpu.fp_status))
3201FOP_COND_S(ngt, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) || float32_le(fst0, fst1, &env->active_fpu.fp_status))
3202
3203#define FOP_COND_PS(op, condl, condh) \
David 'Digit' Turner87350d12014-04-03 15:44:48 +02003204void helper_cmp_ps_ ## op(CPUMIPSState *env, uint64_t fdt0, \
3205 uint64_t fdt1, int cc) \
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08003206{ \
3207 uint32_t fst0 = float32_abs(fdt0 & 0XFFFFFFFF); \
3208 uint32_t fsth0 = float32_abs(fdt0 >> 32); \
3209 uint32_t fst1 = float32_abs(fdt1 & 0XFFFFFFFF); \
3210 uint32_t fsth1 = float32_abs(fdt1 >> 32); \
3211 int cl = condl; \
3212 int ch = condh; \
3213 \
David 'Digit' Turner87350d12014-04-03 15:44:48 +02003214 update_fcr31(env); \
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08003215 if (cl) \
3216 SET_FP_COND(cc, env->active_fpu); \
3217 else \
3218 CLEAR_FP_COND(cc, env->active_fpu); \
3219 if (ch) \
3220 SET_FP_COND(cc + 1, env->active_fpu); \
3221 else \
3222 CLEAR_FP_COND(cc + 1, env->active_fpu); \
3223} \
David 'Digit' Turner87350d12014-04-03 15:44:48 +02003224void helper_cmpabs_ps_ ## op(CPUMIPSState *env, uint64_t fdt0, \
3225 uint64_t fdt1, int cc) \
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08003226{ \
3227 uint32_t fst0 = float32_abs(fdt0 & 0XFFFFFFFF); \
3228 uint32_t fsth0 = float32_abs(fdt0 >> 32); \
3229 uint32_t fst1 = float32_abs(fdt1 & 0XFFFFFFFF); \
3230 uint32_t fsth1 = float32_abs(fdt1 >> 32); \
3231 int cl = condl; \
3232 int ch = condh; \
3233 \
David 'Digit' Turner87350d12014-04-03 15:44:48 +02003234 update_fcr31(env); \
Bhanu Chetlapalli409c7b62012-01-31 16:25:04 -08003235 if (cl) \
3236 SET_FP_COND(cc, env->active_fpu); \
3237 else \
3238 CLEAR_FP_COND(cc, env->active_fpu); \
3239 if (ch) \
3240 SET_FP_COND(cc + 1, env->active_fpu); \
3241 else \
3242 CLEAR_FP_COND(cc + 1, env->active_fpu); \
3243}
3244
3245/* NOTE: the comma operator will make "cond" to eval to false,
3246 * but float*_is_unordered() is still called. */
3247FOP_COND_PS(f, (float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status), 0),
3248 (float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status), 0))
3249FOP_COND_PS(un, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status),
3250 float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status))
3251FOP_COND_PS(eq, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) && float32_eq(fst0, fst1, &env->active_fpu.fp_status),
3252 !float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status) && float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
3253FOP_COND_PS(ueq, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) || float32_eq(fst0, fst1, &env->active_fpu.fp_status),
3254 float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status) || float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
3255FOP_COND_PS(olt, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) && float32_lt(fst0, fst1, &env->active_fpu.fp_status),
3256 !float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status) && float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
3257FOP_COND_PS(ult, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) || float32_lt(fst0, fst1, &env->active_fpu.fp_status),
3258 float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status) || float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
3259FOP_COND_PS(ole, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) && float32_le(fst0, fst1, &env->active_fpu.fp_status),
3260 !float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status) && float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
3261FOP_COND_PS(ule, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) || float32_le(fst0, fst1, &env->active_fpu.fp_status),
3262 float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status) || float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
3263/* NOTE: the comma operator will make "cond" to eval to false,
3264 * but float*_is_unordered() is still called. */
3265FOP_COND_PS(sf, (float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status), 0),
3266 (float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status), 0))
3267FOP_COND_PS(ngle,float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status),
3268 float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status))
3269FOP_COND_PS(seq, !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) && float32_eq(fst0, fst1, &env->active_fpu.fp_status),
3270 !float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status) && float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
3271FOP_COND_PS(ngl, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) || float32_eq(fst0, fst1, &env->active_fpu.fp_status),
3272 float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status) || float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
3273FOP_COND_PS(lt, !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) && float32_lt(fst0, fst1, &env->active_fpu.fp_status),
3274 !float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status) && float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
3275FOP_COND_PS(nge, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) || float32_lt(fst0, fst1, &env->active_fpu.fp_status),
3276 float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status) || float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
3277FOP_COND_PS(le, !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) && float32_le(fst0, fst1, &env->active_fpu.fp_status),
3278 !float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status) && float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
3279FOP_COND_PS(ngt, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) || float32_le(fst0, fst1, &env->active_fpu.fp_status),
3280 float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status) || float32_le(fsth0, fsth1, &env->active_fpu.fp_status))