14acb54baSEdgar E. Iglesias /* 24acb54baSEdgar E. Iglesias * Microblaze helper routines. 34acb54baSEdgar E. Iglesias * 44acb54baSEdgar E. Iglesias * Copyright (c) 2009 Edgar E. Iglesias <edgar.iglesias@gmail.com>. 54acb54baSEdgar E. Iglesias * 64acb54baSEdgar E. Iglesias * This library is free software; you can redistribute it and/or 74acb54baSEdgar E. Iglesias * modify it under the terms of the GNU Lesser General Public 84acb54baSEdgar E. Iglesias * License as published by the Free Software Foundation; either 94acb54baSEdgar E. Iglesias * version 2 of the License, or (at your option) any later version. 104acb54baSEdgar E. Iglesias * 114acb54baSEdgar E. Iglesias * This library is distributed in the hope that it will be useful, 124acb54baSEdgar E. Iglesias * but WITHOUT ANY WARRANTY; without even the implied warranty of 134acb54baSEdgar E. Iglesias * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 144acb54baSEdgar E. Iglesias * Lesser General Public License for more details. 154acb54baSEdgar E. Iglesias * 164acb54baSEdgar E. Iglesias * You should have received a copy of the GNU Lesser General Public 178167ee88SBlue Swirl * License along with this library; if not, see <http://www.gnu.org/licenses/>. 184acb54baSEdgar E. Iglesias */ 194acb54baSEdgar E. Iglesias 204acb54baSEdgar E. Iglesias #include <assert.h> 214acb54baSEdgar E. Iglesias #include "exec.h" 224acb54baSEdgar E. Iglesias #include "helper.h" 234acb54baSEdgar E. Iglesias #include "host-utils.h" 244acb54baSEdgar E. Iglesias 254acb54baSEdgar E. Iglesias #define D(x) 264acb54baSEdgar E. Iglesias 274acb54baSEdgar E. Iglesias #if !defined(CONFIG_USER_ONLY) 284acb54baSEdgar E. Iglesias #define MMUSUFFIX _mmu 294acb54baSEdgar E. Iglesias #define SHIFT 0 304acb54baSEdgar E. Iglesias #include "softmmu_template.h" 314acb54baSEdgar E. Iglesias #define SHIFT 1 324acb54baSEdgar E. Iglesias #include "softmmu_template.h" 334acb54baSEdgar E. Iglesias #define SHIFT 2 344acb54baSEdgar E. Iglesias #include "softmmu_template.h" 354acb54baSEdgar E. Iglesias #define SHIFT 3 364acb54baSEdgar E. Iglesias #include "softmmu_template.h" 374acb54baSEdgar E. Iglesias 384acb54baSEdgar E. Iglesias /* Try to fill the TLB and return an exception if error. If retaddr is 394acb54baSEdgar E. Iglesias NULL, it means that the function was called in C code (i.e. not 404acb54baSEdgar E. Iglesias from generated code or from helper.c) */ 414acb54baSEdgar E. Iglesias /* XXX: fix it to restore all registers */ 424acb54baSEdgar E. Iglesias void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) 434acb54baSEdgar E. Iglesias { 444acb54baSEdgar E. Iglesias TranslationBlock *tb; 454acb54baSEdgar E. Iglesias CPUState *saved_env; 464acb54baSEdgar E. Iglesias unsigned long pc; 474acb54baSEdgar E. Iglesias int ret; 484acb54baSEdgar E. Iglesias 494acb54baSEdgar E. Iglesias /* XXX: hack to restore env in all cases, even if not called from 504acb54baSEdgar E. Iglesias generated code */ 514acb54baSEdgar E. Iglesias saved_env = env; 524acb54baSEdgar E. Iglesias env = cpu_single_env; 534acb54baSEdgar E. Iglesias 544acb54baSEdgar E. Iglesias ret = cpu_mb_handle_mmu_fault(env, addr, is_write, mmu_idx, 1); 554acb54baSEdgar E. Iglesias if (unlikely(ret)) { 564acb54baSEdgar E. Iglesias if (retaddr) { 574acb54baSEdgar E. Iglesias /* now we have a real cpu fault */ 584acb54baSEdgar E. Iglesias pc = (unsigned long)retaddr; 594acb54baSEdgar E. Iglesias tb = tb_find_pc(pc); 604acb54baSEdgar E. Iglesias if (tb) { 614acb54baSEdgar E. Iglesias /* the PC is inside the translated code. It means that we have 624acb54baSEdgar E. Iglesias a virtual CPU fault */ 634acb54baSEdgar E. Iglesias cpu_restore_state(tb, env, pc, NULL); 644acb54baSEdgar E. Iglesias } 654acb54baSEdgar E. Iglesias } 664acb54baSEdgar E. Iglesias cpu_loop_exit(); 674acb54baSEdgar E. Iglesias } 684acb54baSEdgar E. Iglesias env = saved_env; 694acb54baSEdgar E. Iglesias } 704acb54baSEdgar E. Iglesias #endif 714acb54baSEdgar E. Iglesias 726d76d23eSEdgar E. Iglesias void helper_put(uint32_t id, uint32_t ctrl, uint32_t data) 736d76d23eSEdgar E. Iglesias { 746d76d23eSEdgar E. Iglesias int test = ctrl & STREAM_TEST; 756d76d23eSEdgar E. Iglesias int atomic = ctrl & STREAM_ATOMIC; 766d76d23eSEdgar E. Iglesias int control = ctrl & STREAM_CONTROL; 776d76d23eSEdgar E. Iglesias int nonblock = ctrl & STREAM_NONBLOCK; 786d76d23eSEdgar E. Iglesias int exception = ctrl & STREAM_EXCEPTION; 796d76d23eSEdgar E. Iglesias 806d76d23eSEdgar E. Iglesias qemu_log("Unhandled stream put to stream-id=%d data=%x %s%s%s%s%s\n", 816d76d23eSEdgar E. Iglesias id, data, 826d76d23eSEdgar E. Iglesias test ? "t" : "", 836d76d23eSEdgar E. Iglesias nonblock ? "n" : "", 846d76d23eSEdgar E. Iglesias exception ? "e" : "", 856d76d23eSEdgar E. Iglesias control ? "c" : "", 866d76d23eSEdgar E. Iglesias atomic ? "a" : ""); 876d76d23eSEdgar E. Iglesias } 886d76d23eSEdgar E. Iglesias 896d76d23eSEdgar E. Iglesias uint32_t helper_get(uint32_t id, uint32_t ctrl) 906d76d23eSEdgar E. Iglesias { 916d76d23eSEdgar E. Iglesias int test = ctrl & STREAM_TEST; 926d76d23eSEdgar E. Iglesias int atomic = ctrl & STREAM_ATOMIC; 936d76d23eSEdgar E. Iglesias int control = ctrl & STREAM_CONTROL; 946d76d23eSEdgar E. Iglesias int nonblock = ctrl & STREAM_NONBLOCK; 956d76d23eSEdgar E. Iglesias int exception = ctrl & STREAM_EXCEPTION; 966d76d23eSEdgar E. Iglesias 976d76d23eSEdgar E. Iglesias qemu_log("Unhandled stream get from stream-id=%d %s%s%s%s%s\n", 986d76d23eSEdgar E. Iglesias id, 996d76d23eSEdgar E. Iglesias test ? "t" : "", 1006d76d23eSEdgar E. Iglesias nonblock ? "n" : "", 1016d76d23eSEdgar E. Iglesias exception ? "e" : "", 1026d76d23eSEdgar E. Iglesias control ? "c" : "", 1036d76d23eSEdgar E. Iglesias atomic ? "a" : ""); 1046d76d23eSEdgar E. Iglesias return 0xdead0000 | id; 1056d76d23eSEdgar E. Iglesias } 1066d76d23eSEdgar E. Iglesias 1074acb54baSEdgar E. Iglesias void helper_raise_exception(uint32_t index) 1084acb54baSEdgar E. Iglesias { 1094acb54baSEdgar E. Iglesias env->exception_index = index; 1104acb54baSEdgar E. Iglesias cpu_loop_exit(); 1114acb54baSEdgar E. Iglesias } 1124acb54baSEdgar E. Iglesias 1134acb54baSEdgar E. Iglesias void helper_debug(void) 1144acb54baSEdgar E. Iglesias { 1154acb54baSEdgar E. Iglesias int i; 1164acb54baSEdgar E. Iglesias 1174acb54baSEdgar E. Iglesias qemu_log("PC=%8.8x\n", env->sregs[SR_PC]); 1184c24aa0aSMichal Simek qemu_log("rmsr=%x resr=%x rear=%x debug[%x] imm=%x iflags=%x\n", 1194c24aa0aSMichal Simek env->sregs[SR_MSR], env->sregs[SR_ESR], env->sregs[SR_EAR], 12017c52a43SEdgar E. Iglesias env->debug, env->imm, env->iflags); 12117c52a43SEdgar E. Iglesias qemu_log("btaken=%d btarget=%x mode=%s(saved=%s) eip=%d ie=%d\n", 12217c52a43SEdgar E. Iglesias env->btaken, env->btarget, 12317c52a43SEdgar E. Iglesias (env->sregs[SR_MSR] & MSR_UM) ? "user" : "kernel", 12417c52a43SEdgar E. Iglesias (env->sregs[SR_MSR] & MSR_UMS) ? "user" : "kernel", 12517c52a43SEdgar E. Iglesias (env->sregs[SR_MSR] & MSR_EIP), 12617c52a43SEdgar E. Iglesias (env->sregs[SR_MSR] & MSR_IE)); 1274acb54baSEdgar E. Iglesias for (i = 0; i < 32; i++) { 1284acb54baSEdgar E. Iglesias qemu_log("r%2.2d=%8.8x ", i, env->regs[i]); 1294acb54baSEdgar E. Iglesias if ((i + 1) % 4 == 0) 1304acb54baSEdgar E. Iglesias qemu_log("\n"); 1314acb54baSEdgar E. Iglesias } 1324acb54baSEdgar E. Iglesias qemu_log("\n\n"); 1334acb54baSEdgar E. Iglesias } 1344acb54baSEdgar E. Iglesias 1354acb54baSEdgar E. Iglesias static inline uint32_t compute_carry(uint32_t a, uint32_t b, uint32_t cin) 1364acb54baSEdgar E. Iglesias { 1374acb54baSEdgar E. Iglesias uint32_t cout = 0; 1384acb54baSEdgar E. Iglesias 1394acb54baSEdgar E. Iglesias if ((b == ~0) && cin) 1404acb54baSEdgar E. Iglesias cout = 1; 1414acb54baSEdgar E. Iglesias else if ((~0 - a) < (b + cin)) 1424acb54baSEdgar E. Iglesias cout = 1; 1434acb54baSEdgar E. Iglesias return cout; 1444acb54baSEdgar E. Iglesias } 1454acb54baSEdgar E. Iglesias 1464acb54baSEdgar E. Iglesias uint32_t helper_cmp(uint32_t a, uint32_t b) 1474acb54baSEdgar E. Iglesias { 1484acb54baSEdgar E. Iglesias uint32_t t; 1494acb54baSEdgar E. Iglesias 1504acb54baSEdgar E. Iglesias t = b + ~a + 1; 1514acb54baSEdgar E. Iglesias if ((b & 0x80000000) ^ (a & 0x80000000)) 1524acb54baSEdgar E. Iglesias t = (t & 0x7fffffff) | (b & 0x80000000); 1534acb54baSEdgar E. Iglesias return t; 1544acb54baSEdgar E. Iglesias } 1554acb54baSEdgar E. Iglesias 1564acb54baSEdgar E. Iglesias uint32_t helper_cmpu(uint32_t a, uint32_t b) 1574acb54baSEdgar E. Iglesias { 1584acb54baSEdgar E. Iglesias uint32_t t; 1594acb54baSEdgar E. Iglesias 1604acb54baSEdgar E. Iglesias t = b + ~a + 1; 1614acb54baSEdgar E. Iglesias if ((b & 0x80000000) ^ (a & 0x80000000)) 1624acb54baSEdgar E. Iglesias t = (t & 0x7fffffff) | (a & 0x80000000); 1634acb54baSEdgar E. Iglesias return t; 1644acb54baSEdgar E. Iglesias } 1654acb54baSEdgar E. Iglesias 1665d0bb823SEdgar E. Iglesias uint32_t helper_carry(uint32_t a, uint32_t b, uint32_t cf) 1674acb54baSEdgar E. Iglesias { 1685d0bb823SEdgar E. Iglesias uint32_t ncf; 1694acb54baSEdgar E. Iglesias ncf = compute_carry(a, b, cf); 17040cbf5b7SEdgar E. Iglesias return ncf; 1714acb54baSEdgar E. Iglesias } 1724acb54baSEdgar E. Iglesias 1734acb54baSEdgar E. Iglesias static inline int div_prepare(uint32_t a, uint32_t b) 1744acb54baSEdgar E. Iglesias { 1754acb54baSEdgar E. Iglesias if (b == 0) { 1764acb54baSEdgar E. Iglesias env->sregs[SR_MSR] |= MSR_DZ; 177821ebb33SEdgar E. Iglesias 178821ebb33SEdgar E. Iglesias if ((env->sregs[SR_MSR] & MSR_EE) 179821ebb33SEdgar E. Iglesias && !(env->pvr.regs[2] & PVR2_DIV_ZERO_EXC_MASK)) { 180821ebb33SEdgar E. Iglesias env->sregs[SR_ESR] = ESR_EC_DIVZERO; 181821ebb33SEdgar E. Iglesias helper_raise_exception(EXCP_HW_EXCP); 182821ebb33SEdgar E. Iglesias } 1834acb54baSEdgar E. Iglesias return 0; 1844acb54baSEdgar E. Iglesias } 1854acb54baSEdgar E. Iglesias env->sregs[SR_MSR] &= ~MSR_DZ; 1864acb54baSEdgar E. Iglesias return 1; 1874acb54baSEdgar E. Iglesias } 1884acb54baSEdgar E. Iglesias 1894acb54baSEdgar E. Iglesias uint32_t helper_divs(uint32_t a, uint32_t b) 1904acb54baSEdgar E. Iglesias { 1914acb54baSEdgar E. Iglesias if (!div_prepare(a, b)) 1924acb54baSEdgar E. Iglesias return 0; 1934acb54baSEdgar E. Iglesias return (int32_t)a / (int32_t)b; 1944acb54baSEdgar E. Iglesias } 1954acb54baSEdgar E. Iglesias 1964acb54baSEdgar E. Iglesias uint32_t helper_divu(uint32_t a, uint32_t b) 1974acb54baSEdgar E. Iglesias { 1984acb54baSEdgar E. Iglesias if (!div_prepare(a, b)) 1994acb54baSEdgar E. Iglesias return 0; 2004acb54baSEdgar E. Iglesias return a / b; 2014acb54baSEdgar E. Iglesias } 2024acb54baSEdgar E. Iglesias 20397694c57SEdgar E. Iglesias /* raise FPU exception. */ 20497694c57SEdgar E. Iglesias static void raise_fpu_exception(void) 20597694c57SEdgar E. Iglesias { 20697694c57SEdgar E. Iglesias env->sregs[SR_ESR] = ESR_EC_FPU; 20797694c57SEdgar E. Iglesias helper_raise_exception(EXCP_HW_EXCP); 20897694c57SEdgar E. Iglesias } 20997694c57SEdgar E. Iglesias 21097694c57SEdgar E. Iglesias static void update_fpu_flags(int flags) 21197694c57SEdgar E. Iglesias { 21297694c57SEdgar E. Iglesias int raise = 0; 21397694c57SEdgar E. Iglesias 21497694c57SEdgar E. Iglesias if (flags & float_flag_invalid) { 21597694c57SEdgar E. Iglesias env->sregs[SR_FSR] |= FSR_IO; 21697694c57SEdgar E. Iglesias raise = 1; 21797694c57SEdgar E. Iglesias } 21897694c57SEdgar E. Iglesias if (flags & float_flag_divbyzero) { 21997694c57SEdgar E. Iglesias env->sregs[SR_FSR] |= FSR_DZ; 22097694c57SEdgar E. Iglesias raise = 1; 22197694c57SEdgar E. Iglesias } 22297694c57SEdgar E. Iglesias if (flags & float_flag_overflow) { 22397694c57SEdgar E. Iglesias env->sregs[SR_FSR] |= FSR_OF; 22497694c57SEdgar E. Iglesias raise = 1; 22597694c57SEdgar E. Iglesias } 22697694c57SEdgar E. Iglesias if (flags & float_flag_underflow) { 22797694c57SEdgar E. Iglesias env->sregs[SR_FSR] |= FSR_UF; 22897694c57SEdgar E. Iglesias raise = 1; 22997694c57SEdgar E. Iglesias } 23097694c57SEdgar E. Iglesias if (raise 23197694c57SEdgar E. Iglesias && (env->pvr.regs[2] & PVR2_FPU_EXC_MASK) 23297694c57SEdgar E. Iglesias && (env->sregs[SR_MSR] & MSR_EE)) { 23397694c57SEdgar E. Iglesias raise_fpu_exception(); 23497694c57SEdgar E. Iglesias } 23597694c57SEdgar E. Iglesias } 23697694c57SEdgar E. Iglesias 23797694c57SEdgar E. Iglesias uint32_t helper_fadd(uint32_t a, uint32_t b) 23897694c57SEdgar E. Iglesias { 23997694c57SEdgar E. Iglesias CPU_FloatU fd, fa, fb; 24097694c57SEdgar E. Iglesias int flags; 24197694c57SEdgar E. Iglesias 24297694c57SEdgar E. Iglesias set_float_exception_flags(0, &env->fp_status); 24397694c57SEdgar E. Iglesias fa.l = a; 24497694c57SEdgar E. Iglesias fb.l = b; 24597694c57SEdgar E. Iglesias fd.f = float32_add(fa.f, fb.f, &env->fp_status); 24697694c57SEdgar E. Iglesias 24797694c57SEdgar E. Iglesias flags = get_float_exception_flags(&env->fp_status); 24897694c57SEdgar E. Iglesias update_fpu_flags(flags); 24997694c57SEdgar E. Iglesias return fd.l; 25097694c57SEdgar E. Iglesias } 25197694c57SEdgar E. Iglesias 25297694c57SEdgar E. Iglesias uint32_t helper_frsub(uint32_t a, uint32_t b) 25397694c57SEdgar E. Iglesias { 25497694c57SEdgar E. Iglesias CPU_FloatU fd, fa, fb; 25597694c57SEdgar E. Iglesias int flags; 25697694c57SEdgar E. Iglesias 25797694c57SEdgar E. Iglesias set_float_exception_flags(0, &env->fp_status); 25897694c57SEdgar E. Iglesias fa.l = a; 25997694c57SEdgar E. Iglesias fb.l = b; 26097694c57SEdgar E. Iglesias fd.f = float32_sub(fb.f, fa.f, &env->fp_status); 26197694c57SEdgar E. Iglesias flags = get_float_exception_flags(&env->fp_status); 26297694c57SEdgar E. Iglesias update_fpu_flags(flags); 26397694c57SEdgar E. Iglesias return fd.l; 26497694c57SEdgar E. Iglesias } 26597694c57SEdgar E. Iglesias 26697694c57SEdgar E. Iglesias uint32_t helper_fmul(uint32_t a, uint32_t b) 26797694c57SEdgar E. Iglesias { 26897694c57SEdgar E. Iglesias CPU_FloatU fd, fa, fb; 26997694c57SEdgar E. Iglesias int flags; 27097694c57SEdgar E. Iglesias 27197694c57SEdgar E. Iglesias set_float_exception_flags(0, &env->fp_status); 27297694c57SEdgar E. Iglesias fa.l = a; 27397694c57SEdgar E. Iglesias fb.l = b; 27497694c57SEdgar E. Iglesias fd.f = float32_mul(fa.f, fb.f, &env->fp_status); 27597694c57SEdgar E. Iglesias flags = get_float_exception_flags(&env->fp_status); 27697694c57SEdgar E. Iglesias update_fpu_flags(flags); 27797694c57SEdgar E. Iglesias 27897694c57SEdgar E. Iglesias return fd.l; 27997694c57SEdgar E. Iglesias } 28097694c57SEdgar E. Iglesias 28197694c57SEdgar E. Iglesias uint32_t helper_fdiv(uint32_t a, uint32_t b) 28297694c57SEdgar E. Iglesias { 28397694c57SEdgar E. Iglesias CPU_FloatU fd, fa, fb; 28497694c57SEdgar E. Iglesias int flags; 28597694c57SEdgar E. Iglesias 28697694c57SEdgar E. Iglesias set_float_exception_flags(0, &env->fp_status); 28797694c57SEdgar E. Iglesias fa.l = a; 28897694c57SEdgar E. Iglesias fb.l = b; 28997694c57SEdgar E. Iglesias fd.f = float32_div(fb.f, fa.f, &env->fp_status); 29097694c57SEdgar E. Iglesias flags = get_float_exception_flags(&env->fp_status); 29197694c57SEdgar E. Iglesias update_fpu_flags(flags); 29297694c57SEdgar E. Iglesias 29397694c57SEdgar E. Iglesias return fd.l; 29497694c57SEdgar E. Iglesias } 29597694c57SEdgar E. Iglesias 29697694c57SEdgar E. Iglesias uint32_t helper_fcmp_un(uint32_t a, uint32_t b) 29797694c57SEdgar E. Iglesias { 298ef9d48daSEdgar E. Iglesias CPU_FloatU fa, fb; 299ef9d48daSEdgar E. Iglesias uint32_t r = 0; 300ef9d48daSEdgar E. Iglesias 301ef9d48daSEdgar E. Iglesias fa.l = a; 302ef9d48daSEdgar E. Iglesias fb.l = b; 303ef9d48daSEdgar E. Iglesias 304ef9d48daSEdgar E. Iglesias if (float32_is_signaling_nan(fa.f) || float32_is_signaling_nan(fb.f)) { 305ef9d48daSEdgar E. Iglesias update_fpu_flags(float_flag_invalid); 306ef9d48daSEdgar E. Iglesias r = 1; 307ef9d48daSEdgar E. Iglesias } 308ef9d48daSEdgar E. Iglesias 30918569871SPeter Maydell if (float32_is_quiet_nan(fa.f) || float32_is_quiet_nan(fb.f)) { 310ef9d48daSEdgar E. Iglesias r = 1; 311ef9d48daSEdgar E. Iglesias } 312ef9d48daSEdgar E. Iglesias 313ef9d48daSEdgar E. Iglesias return r; 31497694c57SEdgar E. Iglesias } 31597694c57SEdgar E. Iglesias 31697694c57SEdgar E. Iglesias uint32_t helper_fcmp_lt(uint32_t a, uint32_t b) 31797694c57SEdgar E. Iglesias { 31897694c57SEdgar E. Iglesias CPU_FloatU fa, fb; 31997694c57SEdgar E. Iglesias int r; 32097694c57SEdgar E. Iglesias int flags; 32197694c57SEdgar E. Iglesias 32297694c57SEdgar E. Iglesias set_float_exception_flags(0, &env->fp_status); 32397694c57SEdgar E. Iglesias fa.l = a; 32497694c57SEdgar E. Iglesias fb.l = b; 32597694c57SEdgar E. Iglesias r = float32_lt(fb.f, fa.f, &env->fp_status); 32697694c57SEdgar E. Iglesias flags = get_float_exception_flags(&env->fp_status); 32797694c57SEdgar E. Iglesias update_fpu_flags(flags & float_flag_invalid); 32897694c57SEdgar E. Iglesias 32997694c57SEdgar E. Iglesias return r; 33097694c57SEdgar E. Iglesias } 33197694c57SEdgar E. Iglesias 33297694c57SEdgar E. Iglesias uint32_t helper_fcmp_eq(uint32_t a, uint32_t b) 33397694c57SEdgar E. Iglesias { 33497694c57SEdgar E. Iglesias CPU_FloatU fa, fb; 33597694c57SEdgar E. Iglesias int flags; 33697694c57SEdgar E. Iglesias int r; 33797694c57SEdgar E. Iglesias 33897694c57SEdgar E. Iglesias set_float_exception_flags(0, &env->fp_status); 33997694c57SEdgar E. Iglesias fa.l = a; 34097694c57SEdgar E. Iglesias fb.l = b; 34197694c57SEdgar E. Iglesias r = float32_eq(fa.f, fb.f, &env->fp_status); 34297694c57SEdgar E. Iglesias flags = get_float_exception_flags(&env->fp_status); 34397694c57SEdgar E. Iglesias update_fpu_flags(flags & float_flag_invalid); 34497694c57SEdgar E. Iglesias 34597694c57SEdgar E. Iglesias return r; 34697694c57SEdgar E. Iglesias } 34797694c57SEdgar E. Iglesias 34897694c57SEdgar E. Iglesias uint32_t helper_fcmp_le(uint32_t a, uint32_t b) 34997694c57SEdgar E. Iglesias { 35097694c57SEdgar E. Iglesias CPU_FloatU fa, fb; 35197694c57SEdgar E. Iglesias int flags; 35297694c57SEdgar E. Iglesias int r; 35397694c57SEdgar E. Iglesias 35497694c57SEdgar E. Iglesias fa.l = a; 35597694c57SEdgar E. Iglesias fb.l = b; 35697694c57SEdgar E. Iglesias set_float_exception_flags(0, &env->fp_status); 35797694c57SEdgar E. Iglesias r = float32_le(fa.f, fb.f, &env->fp_status); 35897694c57SEdgar E. Iglesias flags = get_float_exception_flags(&env->fp_status); 35997694c57SEdgar E. Iglesias update_fpu_flags(flags & float_flag_invalid); 36097694c57SEdgar E. Iglesias 36197694c57SEdgar E. Iglesias 36297694c57SEdgar E. Iglesias return r; 36397694c57SEdgar E. Iglesias } 36497694c57SEdgar E. Iglesias 36597694c57SEdgar E. Iglesias uint32_t helper_fcmp_gt(uint32_t a, uint32_t b) 36697694c57SEdgar E. Iglesias { 36797694c57SEdgar E. Iglesias CPU_FloatU fa, fb; 36897694c57SEdgar E. Iglesias int flags, r; 36997694c57SEdgar E. Iglesias 37097694c57SEdgar E. Iglesias fa.l = a; 37197694c57SEdgar E. Iglesias fb.l = b; 37297694c57SEdgar E. Iglesias set_float_exception_flags(0, &env->fp_status); 37397694c57SEdgar E. Iglesias r = float32_lt(fa.f, fb.f, &env->fp_status); 37497694c57SEdgar E. Iglesias flags = get_float_exception_flags(&env->fp_status); 37597694c57SEdgar E. Iglesias update_fpu_flags(flags & float_flag_invalid); 37697694c57SEdgar E. Iglesias return r; 37797694c57SEdgar E. Iglesias } 37897694c57SEdgar E. Iglesias 37997694c57SEdgar E. Iglesias uint32_t helper_fcmp_ne(uint32_t a, uint32_t b) 38097694c57SEdgar E. Iglesias { 38197694c57SEdgar E. Iglesias CPU_FloatU fa, fb; 38297694c57SEdgar E. Iglesias int flags, r; 38397694c57SEdgar E. Iglesias 38497694c57SEdgar E. Iglesias fa.l = a; 38597694c57SEdgar E. Iglesias fb.l = b; 38697694c57SEdgar E. Iglesias set_float_exception_flags(0, &env->fp_status); 38797694c57SEdgar E. Iglesias r = !float32_eq(fa.f, fb.f, &env->fp_status); 38897694c57SEdgar E. Iglesias flags = get_float_exception_flags(&env->fp_status); 38997694c57SEdgar E. Iglesias update_fpu_flags(flags & float_flag_invalid); 39097694c57SEdgar E. Iglesias 39197694c57SEdgar E. Iglesias return r; 39297694c57SEdgar E. Iglesias } 39397694c57SEdgar E. Iglesias 39497694c57SEdgar E. Iglesias uint32_t helper_fcmp_ge(uint32_t a, uint32_t b) 39597694c57SEdgar E. Iglesias { 39697694c57SEdgar E. Iglesias CPU_FloatU fa, fb; 39797694c57SEdgar E. Iglesias int flags, r; 39897694c57SEdgar E. Iglesias 39997694c57SEdgar E. Iglesias fa.l = a; 40097694c57SEdgar E. Iglesias fb.l = b; 40197694c57SEdgar E. Iglesias set_float_exception_flags(0, &env->fp_status); 40297694c57SEdgar E. Iglesias r = !float32_lt(fa.f, fb.f, &env->fp_status); 40397694c57SEdgar E. Iglesias flags = get_float_exception_flags(&env->fp_status); 40497694c57SEdgar E. Iglesias update_fpu_flags(flags & float_flag_invalid); 40597694c57SEdgar E. Iglesias 40697694c57SEdgar E. Iglesias return r; 40797694c57SEdgar E. Iglesias } 40897694c57SEdgar E. Iglesias 40997694c57SEdgar E. Iglesias uint32_t helper_flt(uint32_t a) 41097694c57SEdgar E. Iglesias { 41197694c57SEdgar E. Iglesias CPU_FloatU fd, fa; 41297694c57SEdgar E. Iglesias 41397694c57SEdgar E. Iglesias fa.l = a; 41497694c57SEdgar E. Iglesias fd.f = int32_to_float32(fa.l, &env->fp_status); 41597694c57SEdgar E. Iglesias return fd.l; 41697694c57SEdgar E. Iglesias } 41797694c57SEdgar E. Iglesias 41897694c57SEdgar E. Iglesias uint32_t helper_fint(uint32_t a) 41997694c57SEdgar E. Iglesias { 42097694c57SEdgar E. Iglesias CPU_FloatU fa; 42197694c57SEdgar E. Iglesias uint32_t r; 42297694c57SEdgar E. Iglesias int flags; 42397694c57SEdgar E. Iglesias 42497694c57SEdgar E. Iglesias set_float_exception_flags(0, &env->fp_status); 42597694c57SEdgar E. Iglesias fa.l = a; 42697694c57SEdgar E. Iglesias r = float32_to_int32(fa.f, &env->fp_status); 42797694c57SEdgar E. Iglesias flags = get_float_exception_flags(&env->fp_status); 42897694c57SEdgar E. Iglesias update_fpu_flags(flags); 42997694c57SEdgar E. Iglesias 43097694c57SEdgar E. Iglesias return r; 43197694c57SEdgar E. Iglesias } 43297694c57SEdgar E. Iglesias 43397694c57SEdgar E. Iglesias uint32_t helper_fsqrt(uint32_t a) 43497694c57SEdgar E. Iglesias { 43597694c57SEdgar E. Iglesias CPU_FloatU fd, fa; 43697694c57SEdgar E. Iglesias int flags; 43797694c57SEdgar E. Iglesias 43897694c57SEdgar E. Iglesias set_float_exception_flags(0, &env->fp_status); 43997694c57SEdgar E. Iglesias fa.l = a; 44097694c57SEdgar E. Iglesias fd.l = float32_sqrt(fa.f, &env->fp_status); 44197694c57SEdgar E. Iglesias flags = get_float_exception_flags(&env->fp_status); 44297694c57SEdgar E. Iglesias update_fpu_flags(flags); 44397694c57SEdgar E. Iglesias 44497694c57SEdgar E. Iglesias return fd.l; 44597694c57SEdgar E. Iglesias } 44697694c57SEdgar E. Iglesias 4474acb54baSEdgar E. Iglesias uint32_t helper_pcmpbf(uint32_t a, uint32_t b) 4484acb54baSEdgar E. Iglesias { 4494acb54baSEdgar E. Iglesias unsigned int i; 4504acb54baSEdgar E. Iglesias uint32_t mask = 0xff000000; 4514acb54baSEdgar E. Iglesias 4524acb54baSEdgar E. Iglesias for (i = 0; i < 4; i++) { 4534acb54baSEdgar E. Iglesias if ((a & mask) == (b & mask)) 4544acb54baSEdgar E. Iglesias return i + 1; 4554acb54baSEdgar E. Iglesias mask >>= 8; 4564acb54baSEdgar E. Iglesias } 4574acb54baSEdgar E. Iglesias return 0; 4584acb54baSEdgar E. Iglesias } 4594acb54baSEdgar E. Iglesias 4603aa80988SEdgar E. Iglesias void helper_memalign(uint32_t addr, uint32_t dr, uint32_t wr, uint32_t mask) 461968a40f6SEdgar E. Iglesias { 462968a40f6SEdgar E. Iglesias if (addr & mask) { 46397f90cbfSEdgar E. Iglesias qemu_log_mask(CPU_LOG_INT, 46497f90cbfSEdgar E. Iglesias "unaligned access addr=%x mask=%x, wr=%d dr=r%d\n", 46597f90cbfSEdgar E. Iglesias addr, mask, wr, dr); 46697f90cbfSEdgar E. Iglesias env->sregs[SR_EAR] = addr; 467968a40f6SEdgar E. Iglesias env->sregs[SR_ESR] = ESR_EC_UNALIGNED_DATA | (wr << 10) \ 468968a40f6SEdgar E. Iglesias | (dr & 31) << 5; 4693aa80988SEdgar E. Iglesias if (mask == 3) { 470968a40f6SEdgar E. Iglesias env->sregs[SR_ESR] |= 1 << 11; 471968a40f6SEdgar E. Iglesias } 47297f90cbfSEdgar E. Iglesias if (!(env->sregs[SR_MSR] & MSR_EE)) { 47397f90cbfSEdgar E. Iglesias return; 47497f90cbfSEdgar E. Iglesias } 475968a40f6SEdgar E. Iglesias helper_raise_exception(EXCP_HW_EXCP); 476968a40f6SEdgar E. Iglesias } 477968a40f6SEdgar E. Iglesias } 478968a40f6SEdgar E. Iglesias 4794acb54baSEdgar E. Iglesias #if !defined(CONFIG_USER_ONLY) 4804acb54baSEdgar E. Iglesias /* Writes/reads to the MMU's special regs end up here. */ 4814acb54baSEdgar E. Iglesias uint32_t helper_mmu_read(uint32_t rn) 4824acb54baSEdgar E. Iglesias { 4834acb54baSEdgar E. Iglesias return mmu_read(env, rn); 4844acb54baSEdgar E. Iglesias } 4854acb54baSEdgar E. Iglesias 4864acb54baSEdgar E. Iglesias void helper_mmu_write(uint32_t rn, uint32_t v) 4874acb54baSEdgar E. Iglesias { 4884acb54baSEdgar E. Iglesias mmu_write(env, rn, v); 4894acb54baSEdgar E. Iglesias } 490faed1c2aSEdgar E. Iglesias 491c227f099SAnthony Liguori void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec, 492faed1c2aSEdgar E. Iglesias int is_asi, int size) 493faed1c2aSEdgar E. Iglesias { 494faed1c2aSEdgar E. Iglesias CPUState *saved_env; 495e1aa3254SEdgar E. Iglesias 496e1aa3254SEdgar E. Iglesias if (!cpu_single_env) { 497e1aa3254SEdgar E. Iglesias /* XXX: ??? */ 498e1aa3254SEdgar E. Iglesias return; 499e1aa3254SEdgar E. Iglesias } 500e1aa3254SEdgar E. Iglesias 501faed1c2aSEdgar E. Iglesias /* XXX: hack to restore env in all cases, even if not called from 502faed1c2aSEdgar E. Iglesias generated code */ 503faed1c2aSEdgar E. Iglesias saved_env = env; 504faed1c2aSEdgar E. Iglesias env = cpu_single_env; 50597f90cbfSEdgar E. Iglesias qemu_log_mask(CPU_LOG_INT, "Unassigned " TARGET_FMT_plx " wr=%d exe=%d\n", 506faed1c2aSEdgar E. Iglesias addr, is_write, is_exec); 507faed1c2aSEdgar E. Iglesias if (!(env->sregs[SR_MSR] & MSR_EE)) { 50895b279deSEdgar E. Iglesias env = saved_env; 509faed1c2aSEdgar E. Iglesias return; 510faed1c2aSEdgar E. Iglesias } 511faed1c2aSEdgar E. Iglesias 51297f90cbfSEdgar E. Iglesias env->sregs[SR_EAR] = addr; 513faed1c2aSEdgar E. Iglesias if (is_exec) { 51497f90cbfSEdgar E. Iglesias if ((env->pvr.regs[2] & PVR2_IOPB_BUS_EXC_MASK)) { 515faed1c2aSEdgar E. Iglesias env->sregs[SR_ESR] = ESR_EC_INSN_BUS; 516faed1c2aSEdgar E. Iglesias helper_raise_exception(EXCP_HW_EXCP); 517faed1c2aSEdgar E. Iglesias } 518faed1c2aSEdgar E. Iglesias } else { 51997f90cbfSEdgar E. Iglesias if ((env->pvr.regs[2] & PVR2_DOPB_BUS_EXC_MASK)) { 520faed1c2aSEdgar E. Iglesias env->sregs[SR_ESR] = ESR_EC_DATA_BUS; 521faed1c2aSEdgar E. Iglesias helper_raise_exception(EXCP_HW_EXCP); 522faed1c2aSEdgar E. Iglesias } 523faed1c2aSEdgar E. Iglesias } 52495b279deSEdgar E. Iglesias env = saved_env; 525faed1c2aSEdgar E. Iglesias } 5263c7b48b7SPaul Brook #endif 527