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