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