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