| /* |
| * ARM micro operations |
| * |
| * Copyright (c) 2003 Fabrice Bellard |
| * Copyright (c) 2005-2007 CodeSourcery, LLC |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| */ |
| #include "exec.h" |
| |
| void OPPROTO op_addl_T0_T1_cc(void) |
| { |
| unsigned int src1; |
| src1 = T0; |
| T0 += T1; |
| env->NZF = T0; |
| env->CF = T0 < src1; |
| env->VF = (src1 ^ T1 ^ -1) & (src1 ^ T0); |
| } |
| |
| void OPPROTO op_adcl_T0_T1_cc(void) |
| { |
| unsigned int src1; |
| src1 = T0; |
| if (!env->CF) { |
| T0 += T1; |
| env->CF = T0 < src1; |
| } else { |
| T0 += T1 + 1; |
| env->CF = T0 <= src1; |
| } |
| env->VF = (src1 ^ T1 ^ -1) & (src1 ^ T0); |
| env->NZF = T0; |
| FORCE_RET(); |
| } |
| |
| #define OPSUB(sub, sbc, res, T0, T1) \ |
| \ |
| void OPPROTO op_ ## sub ## l_T0_T1_cc(void) \ |
| { \ |
| unsigned int src1; \ |
| src1 = T0; \ |
| T0 -= T1; \ |
| env->NZF = T0; \ |
| env->CF = src1 >= T1; \ |
| env->VF = (src1 ^ T1) & (src1 ^ T0); \ |
| res = T0; \ |
| } \ |
| \ |
| void OPPROTO op_ ## sbc ## l_T0_T1_cc(void) \ |
| { \ |
| unsigned int src1; \ |
| src1 = T0; \ |
| if (!env->CF) { \ |
| T0 = T0 - T1 - 1; \ |
| env->CF = src1 > T1; \ |
| } else { \ |
| T0 = T0 - T1; \ |
| env->CF = src1 >= T1; \ |
| } \ |
| env->VF = (src1 ^ T1) & (src1 ^ T0); \ |
| env->NZF = T0; \ |
| res = T0; \ |
| FORCE_RET(); \ |
| } |
| |
| OPSUB(sub, sbc, T0, T0, T1) |
| |
| OPSUB(rsb, rsc, T0, T1, T0) |
| |
| void OPPROTO op_addq_T0_T1(void) |
| { |
| uint64_t res; |
| res = ((uint64_t)T1 << 32) | T0; |
| res += ((uint64_t)(env->regs[PARAM2]) << 32) | (env->regs[PARAM1]); |
| T1 = res >> 32; |
| T0 = res; |
| } |
| |
| void OPPROTO op_addq_lo_T0_T1(void) |
| { |
| uint64_t res; |
| res = ((uint64_t)T1 << 32) | T0; |
| res += (uint64_t)(env->regs[PARAM1]); |
| T1 = res >> 32; |
| T0 = res; |
| } |
| |
| /* Dual 16-bit accumulate. */ |
| void OPPROTO op_addq_T0_T1_dual(void) |
| { |
| uint64_t res; |
| res = ((uint64_t)(env->regs[PARAM2]) << 32) | (env->regs[PARAM1]); |
| res += (int32_t)T0; |
| res += (int32_t)T1; |
| env->regs[PARAM1] = (uint32_t)res; |
| env->regs[PARAM2] = res >> 32; |
| } |
| |
| /* Dual 16-bit subtract accumulate. */ |
| void OPPROTO op_subq_T0_T1_dual(void) |
| { |
| uint64_t res; |
| res = ((uint64_t)(env->regs[PARAM2]) << 32) | (env->regs[PARAM1]); |
| res += (int32_t)T0; |
| res -= (int32_t)T1; |
| env->regs[PARAM1] = (uint32_t)res; |
| env->regs[PARAM2] = res >> 32; |
| } |
| |
| void OPPROTO op_logicq_cc(void) |
| { |
| env->NZF = (T1 & 0x80000000) | ((T0 | T1) != 0); |
| } |
| |
| /* memory access */ |
| |
| #define MEMSUFFIX _raw |
| #include "op_mem.h" |
| |
| #if !defined(CONFIG_USER_ONLY) |
| #define MEMSUFFIX _user |
| #include "op_mem.h" |
| #define MEMSUFFIX _kernel |
| #include "op_mem.h" |
| #endif |
| |
| void OPPROTO op_clrex(void) |
| { |
| cpu_lock(); |
| helper_clrex(env); |
| cpu_unlock(); |
| } |
| |
| /* T1 based, use T0 as shift count */ |
| |
| void OPPROTO op_shll_T1_T0(void) |
| { |
| int shift; |
| shift = T0 & 0xff; |
| if (shift >= 32) |
| T1 = 0; |
| else |
| T1 = T1 << shift; |
| FORCE_RET(); |
| } |
| |
| void OPPROTO op_shrl_T1_T0(void) |
| { |
| int shift; |
| shift = T0 & 0xff; |
| if (shift >= 32) |
| T1 = 0; |
| else |
| T1 = (uint32_t)T1 >> shift; |
| FORCE_RET(); |
| } |
| |
| void OPPROTO op_sarl_T1_T0(void) |
| { |
| int shift; |
| shift = T0 & 0xff; |
| if (shift >= 32) |
| shift = 31; |
| T1 = (int32_t)T1 >> shift; |
| } |
| |
| void OPPROTO op_rorl_T1_T0(void) |
| { |
| int shift; |
| shift = T0 & 0x1f; |
| if (shift) { |
| T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift)); |
| } |
| FORCE_RET(); |
| } |
| |
| /* T1 based, use T0 as shift count and compute CF */ |
| |
| void OPPROTO op_shll_T1_T0_cc(void) |
| { |
| int shift; |
| shift = T0 & 0xff; |
| if (shift >= 32) { |
| if (shift == 32) |
| env->CF = T1 & 1; |
| else |
| env->CF = 0; |
| T1 = 0; |
| } else if (shift != 0) { |
| env->CF = (T1 >> (32 - shift)) & 1; |
| T1 = T1 << shift; |
| } |
| FORCE_RET(); |
| } |
| |
| void OPPROTO op_shrl_T1_T0_cc(void) |
| { |
| int shift; |
| shift = T0 & 0xff; |
| if (shift >= 32) { |
| if (shift == 32) |
| env->CF = (T1 >> 31) & 1; |
| else |
| env->CF = 0; |
| T1 = 0; |
| } else if (shift != 0) { |
| env->CF = (T1 >> (shift - 1)) & 1; |
| T1 = (uint32_t)T1 >> shift; |
| } |
| FORCE_RET(); |
| } |
| |
| void OPPROTO op_sarl_T1_T0_cc(void) |
| { |
| int shift; |
| shift = T0 & 0xff; |
| if (shift >= 32) { |
| env->CF = (T1 >> 31) & 1; |
| T1 = (int32_t)T1 >> 31; |
| } else if (shift != 0) { |
| env->CF = (T1 >> (shift - 1)) & 1; |
| T1 = (int32_t)T1 >> shift; |
| } |
| FORCE_RET(); |
| } |
| |
| void OPPROTO op_rorl_T1_T0_cc(void) |
| { |
| int shift1, shift; |
| shift1 = T0 & 0xff; |
| shift = shift1 & 0x1f; |
| if (shift == 0) { |
| if (shift1 != 0) |
| env->CF = (T1 >> 31) & 1; |
| } else { |
| env->CF = (T1 >> (shift - 1)) & 1; |
| T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift)); |
| } |
| FORCE_RET(); |
| } |
| |
| void OPPROTO op_movl_cp_T0(void) |
| { |
| helper_set_cp(env, PARAM1, T0); |
| FORCE_RET(); |
| } |
| |
| void OPPROTO op_movl_T0_cp(void) |
| { |
| T0 = helper_get_cp(env, PARAM1); |
| FORCE_RET(); |
| } |
| |
| void OPPROTO op_movl_cp15_T0(void) |
| { |
| helper_set_cp15(env, PARAM1, T0); |
| FORCE_RET(); |
| } |
| |
| void OPPROTO op_movl_T0_cp15(void) |
| { |
| T0 = helper_get_cp15(env, PARAM1); |
| FORCE_RET(); |
| } |
| |
| void OPPROTO op_v7m_mrs_T0(void) |
| { |
| T0 = helper_v7m_mrs(env, PARAM1); |
| } |
| |
| void OPPROTO op_v7m_msr_T0(void) |
| { |
| helper_v7m_msr(env, PARAM1, T0); |
| } |
| |
| void OPPROTO op_movl_T0_sp(void) |
| { |
| if (PARAM1 == env->v7m.current_sp) |
| T0 = env->regs[13]; |
| else |
| T0 = env->v7m.other_sp; |
| FORCE_RET(); |
| } |
| |
| #include "op_neon.h" |
| |
| /* iwMMXt support */ |
| #include "op_iwmmxt.c" |