Home | History | Annotate | Download | only in target-arm
      1 /*
      2  *  ARM helper routines
      3  *
      4  *  Copyright (c) 2005-2007 CodeSourcery, LLC
      5  *
      6  * This library is free software; you can redistribute it and/or
      7  * modify it under the terms of the GNU Lesser General Public
      8  * License as published by the Free Software Foundation; either
      9  * version 2 of the License, or (at your option) any later version.
     10  *
     11  * This library is distributed in the hope that it will be useful,
     12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14  * Lesser General Public License for more details.
     15  *
     16  * You should have received a copy of the GNU Lesser General Public
     17  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
     18  */
     19 #include "cpu.h"
     20 #include "tcg.h"
     21 #include "helper.h"
     22 
     23 #define SIGNBIT (uint32_t)0x80000000
     24 #define SIGNBIT64 ((uint64_t)1 << 63)
     25 
     26 #if !defined(CONFIG_USER_ONLY)
     27 static void raise_exception(CPUARMState *env, int tt)
     28 {
     29     env->exception_index = tt;
     30     cpu_loop_exit(env);
     31 }
     32 #endif
     33 
     34 uint32_t HELPER(neon_tbl)(CPUARMState *env, uint32_t ireg, uint32_t def,
     35                           uint32_t rn, uint32_t maxindex)
     36 {
     37     uint32_t val;
     38     uint32_t tmp;
     39     int index;
     40     int shift;
     41     uint64_t *table;
     42     table = (uint64_t *)&env->vfp.regs[rn];
     43     val = 0;
     44     for (shift = 0; shift < 32; shift += 8) {
     45         index = (ireg >> shift) & 0xff;
     46         if (index < maxindex) {
     47             tmp = (table[index >> 3] >> ((index & 7) << 3)) & 0xff;
     48             val |= tmp << shift;
     49         } else {
     50             val |= def & (0xff << shift);
     51         }
     52     }
     53     return val;
     54 }
     55 
     56 #undef env
     57 
     58 #if !defined(CONFIG_USER_ONLY)
     59 
     60 
     61 #define MMUSUFFIX _mmu
     62 
     63 #define SHIFT 0
     64 #include "exec/softmmu_template.h"
     65 
     66 #define SHIFT 1
     67 #include "exec/softmmu_template.h"
     68 
     69 #define SHIFT 2
     70 #include "exec/softmmu_template.h"
     71 
     72 #define SHIFT 3
     73 #include "exec/softmmu_template.h"
     74 
     75 /* try to fill the TLB and return an exception if error. If retaddr is
     76    NULL, it means that the function was called in C code (i.e. not
     77    from generated code or from helper.c) */
     78 void tlb_fill(CPUARMState *env, target_ulong addr, int is_write, int mmu_idx,
     79               uintptr_t retaddr)
     80 {
     81     int ret;
     82 
     83     ret = cpu_arm_handle_mmu_fault(env, addr, is_write, mmu_idx);
     84     if (unlikely(ret)) {
     85         if (retaddr) {
     86             /* now we have a real cpu fault */
     87             cpu_restore_state(env, retaddr);
     88         }
     89         raise_exception(env, env->exception_index);
     90     }
     91 }
     92 
     93 void HELPER(set_cp)(CPUARMState *env, uint32_t insn, uint32_t val)
     94 {
     95     int cp_num = (insn >> 8) & 0xf;
     96     int cp_info = (insn >> 5) & 7;
     97     int src = (insn >> 16) & 0xf;
     98     int operand = insn & 0xf;
     99 
    100     if (env->cp[cp_num].cp_write)
    101         env->cp[cp_num].cp_write(env->cp[cp_num].opaque,
    102                                  cp_info, src, operand, val, (void*)GETPC());
    103         }
    104 
    105 uint32_t HELPER(get_cp)(CPUARMState *env, uint32_t insn)
    106 {
    107     int cp_num = (insn >> 8) & 0xf;
    108     int cp_info = (insn >> 5) & 7;
    109     int dest = (insn >> 16) & 0xf;
    110     int operand = insn & 0xf;
    111 
    112     if (env->cp[cp_num].cp_read)
    113         return env->cp[cp_num].cp_read(env->cp[cp_num].opaque,
    114                                        cp_info, dest, operand, (void*)GETPC());
    115         return 0;
    116 }
    117 
    118 #else
    119 
    120 void HELPER(set_cp)(CPUARMState *env, uint32_t insn, uint32_t val)
    121 {
    122     int op1 = (insn >> 8) & 0xf;
    123     cpu_abort(env, "cp%i insn %08x\n", op1, insn);
    124     return;
    125 }
    126 
    127 uint32_t HELPER(get_cp)(CPUARMState *env, uint32_t insn)
    128 {
    129     int op1 = (insn >> 8) & 0xf;
    130     cpu_abort(env, "cp%i insn %08x\n", op1, insn);
    131     return 0;
    132 }
    133 
    134 #endif
    135 
    136 uint32_t HELPER(add_setq)(CPUARMState *env, uint32_t a, uint32_t b)
    137 {
    138     uint32_t res = a + b;
    139     if (((res ^ a) & SIGNBIT) && !((a ^ b) & SIGNBIT))
    140         env->QF = 1;
    141     return res;
    142 }
    143 
    144 uint32_t HELPER(add_saturate)(CPUARMState *env, uint32_t a, uint32_t b)
    145 {
    146     uint32_t res = a + b;
    147     if (((res ^ a) & SIGNBIT) && !((a ^ b) & SIGNBIT)) {
    148         env->QF = 1;
    149         res = ~(((int32_t)a >> 31) ^ SIGNBIT);
    150     }
    151     return res;
    152 }
    153 
    154 uint32_t HELPER(sub_saturate)(CPUARMState *env, uint32_t a, uint32_t b)
    155 {
    156     uint32_t res = a - b;
    157     if (((res ^ a) & SIGNBIT) && ((a ^ b) & SIGNBIT)) {
    158         env->QF = 1;
    159         res = ~(((int32_t)a >> 31) ^ SIGNBIT);
    160     }
    161     return res;
    162 }
    163 
    164 uint32_t HELPER(double_saturate)(CPUARMState *env, int32_t val)
    165 {
    166     uint32_t res;
    167     if (val >= 0x40000000) {
    168         res = ~SIGNBIT;
    169         env->QF = 1;
    170     } else if (val <= (int32_t)0xc0000000) {
    171         res = SIGNBIT;
    172         env->QF = 1;
    173     } else {
    174         res = val << 1;
    175     }
    176     return res;
    177 }
    178 
    179 uint32_t HELPER(add_usaturate)(CPUARMState *env, uint32_t a, uint32_t b)
    180 {
    181     uint32_t res = a + b;
    182     if (res < a) {
    183         env->QF = 1;
    184         res = ~0;
    185     }
    186     return res;
    187 }
    188 
    189 uint32_t HELPER(sub_usaturate)(CPUARMState *env, uint32_t a, uint32_t b)
    190 {
    191     uint32_t res = a - b;
    192     if (res > a) {
    193         env->QF = 1;
    194         res = 0;
    195     }
    196     return res;
    197 }
    198 
    199 /* Signed saturation.  */
    200 static inline uint32_t do_ssat(CPUARMState *env, int32_t val, int shift)
    201 {
    202     int32_t top;
    203     uint32_t mask;
    204 
    205     top = val >> shift;
    206     mask = (1u << shift) - 1;
    207     if (top > 0) {
    208         env->QF = 1;
    209         return mask;
    210     } else if (top < -1) {
    211         env->QF = 1;
    212         return ~mask;
    213     }
    214     return val;
    215 }
    216 
    217 /* Unsigned saturation.  */
    218 static inline uint32_t do_usat(CPUARMState *env, int32_t val, int shift)
    219 {
    220     uint32_t max;
    221 
    222     max = (1u << shift) - 1;
    223     if (val < 0) {
    224         env->QF = 1;
    225         return 0;
    226     } else if (val > max) {
    227         env->QF = 1;
    228         return max;
    229     }
    230     return val;
    231 }
    232 
    233 /* Signed saturate.  */
    234 uint32_t HELPER(ssat)(CPUARMState *env, uint32_t x, uint32_t shift)
    235 {
    236     return do_ssat(env, x, shift);
    237 }
    238 
    239 /* Dual halfword signed saturate.  */
    240 uint32_t HELPER(ssat16)(CPUARMState *env, uint32_t x, uint32_t shift)
    241 {
    242     uint32_t res;
    243 
    244     res = (uint16_t)do_ssat(env, (int16_t)x, shift);
    245     res |= do_ssat(env, ((int32_t)x) >> 16, shift) << 16;
    246     return res;
    247 }
    248 
    249 /* Unsigned saturate.  */
    250 uint32_t HELPER(usat)(CPUARMState *env, uint32_t x, uint32_t shift)
    251 {
    252     return do_usat(env, x, shift);
    253 }
    254 
    255 /* Dual halfword unsigned saturate.  */
    256 uint32_t HELPER(usat16)(CPUARMState *env, uint32_t x, uint32_t shift)
    257 {
    258     uint32_t res;
    259 
    260     res = (uint16_t)do_usat(env, (int16_t)x, shift);
    261     res |= do_usat(env, ((int32_t)x) >> 16, shift) << 16;
    262     return res;
    263 }
    264 
    265 void HELPER(wfi)(CPUARMState *env)
    266 {
    267     env->exception_index = EXCP_HLT;
    268     ENV_GET_CPU(env)->halted = 1;
    269     cpu_loop_exit(env);
    270 }
    271 
    272 void HELPER(exception)(CPUARMState *env, uint32_t excp)
    273 {
    274     env->exception_index = excp;
    275     cpu_loop_exit(env);
    276 }
    277 
    278 uint32_t HELPER(cpsr_read)(CPUARMState *env)
    279 {
    280     return cpsr_read(env) & ~CPSR_EXEC;
    281 }
    282 
    283 void HELPER(cpsr_write)(CPUARMState *env, uint32_t val, uint32_t mask)
    284 {
    285     cpsr_write(env, val, mask);
    286 }
    287 
    288 /* Access to user mode registers from privileged modes.  */
    289 uint32_t HELPER(get_user_reg)(CPUARMState *env, uint32_t regno)
    290 {
    291     uint32_t val;
    292 
    293     if (regno == 13) {
    294         val = env->banked_r13[0];
    295     } else if (regno == 14) {
    296         val = env->banked_r14[0];
    297     } else if (regno >= 8
    298                && (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_FIQ) {
    299         val = env->usr_regs[regno - 8];
    300     } else {
    301         val = env->regs[regno];
    302     }
    303     return val;
    304 }
    305 
    306 void HELPER(set_user_reg)(CPUARMState *env, uint32_t regno, uint32_t val)
    307 {
    308     if (regno == 13) {
    309         env->banked_r13[0] = val;
    310     } else if (regno == 14) {
    311         env->banked_r14[0] = val;
    312     } else if (regno >= 8
    313                && (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_FIQ) {
    314         env->usr_regs[regno - 8] = val;
    315     } else {
    316         env->regs[regno] = val;
    317     }
    318 }
    319 
    320 /* ??? Flag setting arithmetic is awkward because we need to do comparisons.
    321    The only way to do that in TCG is a conditional branch, which clobbers
    322    all our temporaries.  For now implement these as helper functions.  */
    323 
    324 uint32_t HELPER (add_cc)(CPUARMState *env, uint32_t a, uint32_t b)
    325 {
    326     uint32_t result;
    327     result = a + b;
    328     env->NF = env->ZF = result;
    329     env->CF = result < a;
    330     env->VF = (a ^ b ^ -1) & (a ^ result);
    331     return result;
    332 }
    333 
    334 uint32_t HELPER(adc_cc)(CPUARMState *env, uint32_t a, uint32_t b)
    335 {
    336     uint32_t result;
    337     if (!env->CF) {
    338         result = a + b;
    339         env->CF = result < a;
    340     } else {
    341         result = a + b + 1;
    342         env->CF = result <= a;
    343     }
    344     env->VF = (a ^ b ^ -1) & (a ^ result);
    345     env->NF = env->ZF = result;
    346     return result;
    347 }
    348 
    349 uint32_t HELPER(sub_cc)(CPUARMState *env, uint32_t a, uint32_t b)
    350 {
    351     uint32_t result;
    352     result = a - b;
    353     env->NF = env->ZF = result;
    354     env->CF = a >= b;
    355     env->VF = (a ^ b) & (a ^ result);
    356     return result;
    357 }
    358 
    359 uint32_t HELPER(sbc_cc)(CPUARMState *env, uint32_t a, uint32_t b)
    360 {
    361     uint32_t result;
    362     if (!env->CF) {
    363         result = a - b - 1;
    364         env->CF = a > b;
    365     } else {
    366         result = a - b;
    367         env->CF = a >= b;
    368     }
    369     env->VF = (a ^ b) & (a ^ result);
    370     env->NF = env->ZF = result;
    371     return result;
    372 }
    373 
    374 /* Similarly for variable shift instructions.  */
    375 
    376 uint32_t HELPER(shl)(uint32_t x, uint32_t i)
    377 {
    378     int shift = i & 0xff;
    379     if (shift >= 32)
    380         return 0;
    381     return x << shift;
    382 }
    383 
    384 uint32_t HELPER(shr)(uint32_t x, uint32_t i)
    385 {
    386     int shift = i & 0xff;
    387     if (shift >= 32)
    388         return 0;
    389     return (uint32_t)x >> shift;
    390 }
    391 
    392 uint32_t HELPER(sar)(uint32_t x, uint32_t i)
    393 {
    394     int shift = i & 0xff;
    395     if (shift >= 32)
    396         shift = 31;
    397     return (int32_t)x >> shift;
    398 }
    399 
    400 uint32_t HELPER(shl_cc)(CPUARMState *env, uint32_t x, uint32_t i)
    401 {
    402     int shift = i & 0xff;
    403     if (shift >= 32) {
    404         if (shift == 32)
    405             env->CF = x & 1;
    406         else
    407             env->CF = 0;
    408         return 0;
    409     } else if (shift != 0) {
    410         env->CF = (x >> (32 - shift)) & 1;
    411         return x << shift;
    412     }
    413     return x;
    414 }
    415 
    416 uint32_t HELPER(shr_cc)(CPUARMState *env, uint32_t x, uint32_t i)
    417 {
    418     int shift = i & 0xff;
    419     if (shift >= 32) {
    420         if (shift == 32)
    421             env->CF = (x >> 31) & 1;
    422         else
    423             env->CF = 0;
    424         return 0;
    425     } else if (shift != 0) {
    426         env->CF = (x >> (shift - 1)) & 1;
    427         return x >> shift;
    428     }
    429     return x;
    430 }
    431 
    432 uint32_t HELPER(sar_cc)(CPUARMState *env, uint32_t x, uint32_t i)
    433 {
    434     int shift = i & 0xff;
    435     if (shift >= 32) {
    436         env->CF = (x >> 31) & 1;
    437         return (int32_t)x >> 31;
    438     } else if (shift != 0) {
    439         env->CF = (x >> (shift - 1)) & 1;
    440         return (int32_t)x >> shift;
    441     }
    442     return x;
    443 }
    444 
    445 uint32_t HELPER(ror_cc)(CPUARMState *env, uint32_t x, uint32_t i)
    446 {
    447     int shift1, shift;
    448     shift1 = i & 0xff;
    449     shift = shift1 & 0x1f;
    450     if (shift == 0) {
    451         if (shift1 != 0)
    452             env->CF = (x >> 31) & 1;
    453         return x;
    454     } else {
    455         env->CF = (x >> (shift - 1)) & 1;
    456         return ((uint32_t)x >> shift) | (x << (32 - shift));
    457     }
    458 }
    459 
    460 void HELPER(neon_vldst_all)(CPUARMState *env, uint32_t insn)
    461 {
    462 #if defined(CONFIG_USER_ONLY)
    463 #define LDB(addr) ldub(addr)
    464 #define LDW(addr) lduw(addr)
    465 #define LDL(addr) ldl(addr)
    466 #define LDQ(addr) ldq(addr)
    467 #define STB(addr, val) stb(addr, val)
    468 #define STW(addr, val) stw(addr, val)
    469 #define STL(addr, val) stl(addr, val)
    470 #define STQ(addr, val) stq(addr, val)
    471 #else
    472     int user = cpu_mmu_index(env);
    473 #define LDB(addr) helper_ldb_mmu(env, addr, user)
    474 #define LDW(addr) helper_le_lduw_mmu(env, addr, user, GETPC())
    475 #define LDL(addr) helper_le_ldul_mmu(env, addr, user, GETPC())
    476 #define LDQ(addr) helper_le_ldq_mmu(env, addr, user, GETPC())
    477 #define STB(addr, val) helper_stb_mmu(env, addr, val, user)
    478 #define STW(addr, val) helper_le_stw_mmu(env, addr, val, user, GETPC())
    479 #define STL(addr, val) helper_le_stl_mmu(env, addr, val, user, GETPC())
    480 #define STQ(addr, val) helper_le_stq_mmu(env, addr, val, user, GETPC())
    481 #endif
    482     static const struct {
    483         int nregs;
    484         int interleave;
    485         int spacing;
    486     } neon_ls_element_type[11] = {
    487         {4, 4, 1},
    488         {4, 4, 2},
    489         {4, 1, 1},
    490         {4, 2, 1},
    491         {3, 3, 1},
    492         {3, 3, 2},
    493         {3, 1, 1},
    494         {1, 1, 1},
    495         {2, 2, 1},
    496         {2, 2, 2},
    497         {2, 1, 1}
    498     };
    499 
    500     const int op = (insn >> 8) & 0xf;
    501     const int size = (insn >> 6) & 3;
    502     int rd = ((insn >> 12) & 0x0f) | ((insn >> 18) & 0x10);
    503     const int rn = (insn >> 16) & 0xf;
    504     const int load = (insn & (1 << 21)) != 0;
    505     const int nregs = neon_ls_element_type[op].nregs;
    506     const int interleave = neon_ls_element_type[op].interleave;
    507     const int spacing = neon_ls_element_type[op].spacing;
    508     uint32_t addr = env->regs[rn];
    509     const int stride = (1 << size) * interleave;
    510     int i, reg;
    511     uint64_t tmp64;
    512 
    513     for (reg = 0; reg < nregs; reg++) {
    514         if (interleave > 2 || (interleave == 2 && nregs == 2)) {
    515             addr = env->regs[rn] + (1 << size) * reg;
    516         } else if (interleave == 2 && nregs == 4 && reg == 2) {
    517             addr = env->regs[rn] + (1 << size);
    518         }
    519         switch (size) {
    520             case 3:
    521                 if (load) {
    522                     env->vfp.regs[rd] = make_float64(LDQ(addr));
    523                 } else {
    524                     STQ(addr, float64_val(env->vfp.regs[rd]));
    525                 }
    526                 addr += stride;
    527                 break;
    528             case 2:
    529                 if (load) {
    530                     tmp64 = (uint32_t)LDL(addr);
    531                     addr += stride;
    532                     tmp64 |= (uint64_t)LDL(addr) << 32;
    533                     addr += stride;
    534                     env->vfp.regs[rd] = make_float64(tmp64);
    535                 } else {
    536                     tmp64 = float64_val(env->vfp.regs[rd]);
    537                     STL(addr, tmp64);
    538                     addr += stride;
    539                     STL(addr, tmp64 >> 32);
    540                     addr += stride;
    541                 }
    542                 break;
    543             case 1:
    544                 if (load) {
    545                     tmp64 = 0ull;
    546                     for (i = 0; i < 4; i++, addr += stride) {
    547                         tmp64 |= (uint64_t)LDW(addr) << (i * 16);
    548                     }
    549                     env->vfp.regs[rd] = make_float64(tmp64);
    550                 } else {
    551                     tmp64 = float64_val(env->vfp.regs[rd]);
    552                     for (i = 0; i < 4; i++, addr += stride, tmp64 >>= 16) {
    553                         STW(addr, tmp64);
    554                     }
    555                 }
    556                 break;
    557             case 0:
    558                 if (load) {
    559                     tmp64 = 0ull;
    560                     for (i = 0; i < 8; i++, addr += stride) {
    561                         tmp64 |= (uint64_t)LDB(addr) << (i * 8);
    562                     }
    563                     env->vfp.regs[rd] = make_float64(tmp64);
    564                 } else {
    565                     tmp64 = float64_val(env->vfp.regs[rd]);
    566                     for (i = 0; i < 8; i++, addr += stride, tmp64 >>= 8) {
    567                         STB(addr, tmp64);
    568                     }
    569                 }
    570                 break;
    571         }
    572         rd += spacing;
    573     }
    574 #undef LDB
    575 #undef LDW
    576 #undef LDL
    577 #undef LDQ
    578 #undef STB
    579 #undef STW
    580 #undef STL
    581 #undef STQ
    582 }
    583