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