qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

op_helper.c (11127B)


      1 /*
      2  *  Microblaze helper routines.
      3  *
      4  *  Copyright (c) 2009 Edgar E. Iglesias <edgar.iglesias@gmail.com>.
      5  *  Copyright (c) 2009-2012 PetaLogix Qld Pty Ltd.
      6  *
      7  * This library is free software; you can redistribute it and/or
      8  * modify it under the terms of the GNU Lesser General Public
      9  * License as published by the Free Software Foundation; either
     10  * version 2.1 of the License, or (at your option) any later version.
     11  *
     12  * This library is distributed in the hope that it will be useful,
     13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     15  * Lesser General Public License for more details.
     16  *
     17  * You should have received a copy of the GNU Lesser General Public
     18  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
     19  */
     20 
     21 #include "qemu/osdep.h"
     22 #include "qemu/log.h"
     23 #include "cpu.h"
     24 #include "exec/helper-proto.h"
     25 #include "qemu/host-utils.h"
     26 #include "exec/exec-all.h"
     27 #include "exec/cpu_ldst.h"
     28 #include "fpu/softfloat.h"
     29 
     30 void helper_put(uint32_t id, uint32_t ctrl, uint32_t data)
     31 {
     32     int test = ctrl & STREAM_TEST;
     33     int atomic = ctrl & STREAM_ATOMIC;
     34     int control = ctrl & STREAM_CONTROL;
     35     int nonblock = ctrl & STREAM_NONBLOCK;
     36     int exception = ctrl & STREAM_EXCEPTION;
     37 
     38     qemu_log_mask(LOG_UNIMP, "Unhandled stream put to stream-id=%d data=%x %s%s%s%s%s\n",
     39              id, data,
     40              test ? "t" : "",
     41              nonblock ? "n" : "",
     42              exception ? "e" : "",
     43              control ? "c" : "",
     44              atomic ? "a" : "");
     45 }
     46 
     47 uint32_t helper_get(uint32_t id, uint32_t ctrl)
     48 {
     49     int test = ctrl & STREAM_TEST;
     50     int atomic = ctrl & STREAM_ATOMIC;
     51     int control = ctrl & STREAM_CONTROL;
     52     int nonblock = ctrl & STREAM_NONBLOCK;
     53     int exception = ctrl & STREAM_EXCEPTION;
     54 
     55     qemu_log_mask(LOG_UNIMP, "Unhandled stream get from stream-id=%d %s%s%s%s%s\n",
     56              id,
     57              test ? "t" : "",
     58              nonblock ? "n" : "",
     59              exception ? "e" : "",
     60              control ? "c" : "",
     61              atomic ? "a" : "");
     62     return 0xdead0000 | id;
     63 }
     64 
     65 void helper_raise_exception(CPUMBState *env, uint32_t index)
     66 {
     67     CPUState *cs = env_cpu(env);
     68 
     69     cs->exception_index = index;
     70     cpu_loop_exit(cs);
     71 }
     72 
     73 static bool check_divz(CPUMBState *env, uint32_t a, uint32_t b, uintptr_t ra)
     74 {
     75     if (unlikely(b == 0)) {
     76         env->msr |= MSR_DZ;
     77 
     78         if ((env->msr & MSR_EE) &&
     79             env_archcpu(env)->cfg.div_zero_exception) {
     80             CPUState *cs = env_cpu(env);
     81 
     82             env->esr = ESR_EC_DIVZERO;
     83             cs->exception_index = EXCP_HW_EXCP;
     84             cpu_loop_exit_restore(cs, ra);
     85         }
     86         return false;
     87     }
     88     return true;
     89 }
     90 
     91 uint32_t helper_divs(CPUMBState *env, uint32_t a, uint32_t b)
     92 {
     93     if (!check_divz(env, a, b, GETPC())) {
     94         return 0;
     95     }
     96     return (int32_t)a / (int32_t)b;
     97 }
     98 
     99 uint32_t helper_divu(CPUMBState *env, uint32_t a, uint32_t b)
    100 {
    101     if (!check_divz(env, a, b, GETPC())) {
    102         return 0;
    103     }
    104     return a / b;
    105 }
    106 
    107 /* raise FPU exception.  */
    108 static void raise_fpu_exception(CPUMBState *env, uintptr_t ra)
    109 {
    110     CPUState *cs = env_cpu(env);
    111 
    112     env->esr = ESR_EC_FPU;
    113     cs->exception_index = EXCP_HW_EXCP;
    114     cpu_loop_exit_restore(cs, ra);
    115 }
    116 
    117 static void update_fpu_flags(CPUMBState *env, int flags, uintptr_t ra)
    118 {
    119     int raise = 0;
    120 
    121     if (flags & float_flag_invalid) {
    122         env->fsr |= FSR_IO;
    123         raise = 1;
    124     }
    125     if (flags & float_flag_divbyzero) {
    126         env->fsr |= FSR_DZ;
    127         raise = 1;
    128     }
    129     if (flags & float_flag_overflow) {
    130         env->fsr |= FSR_OF;
    131         raise = 1;
    132     }
    133     if (flags & float_flag_underflow) {
    134         env->fsr |= FSR_UF;
    135         raise = 1;
    136     }
    137     if (raise
    138         && (env_archcpu(env)->cfg.pvr_regs[2] & PVR2_FPU_EXC_MASK)
    139         && (env->msr & MSR_EE)) {
    140         raise_fpu_exception(env, ra);
    141     }
    142 }
    143 
    144 uint32_t helper_fadd(CPUMBState *env, uint32_t a, uint32_t b)
    145 {
    146     CPU_FloatU fd, fa, fb;
    147     int flags;
    148 
    149     set_float_exception_flags(0, &env->fp_status);
    150     fa.l = a;
    151     fb.l = b;
    152     fd.f = float32_add(fa.f, fb.f, &env->fp_status);
    153 
    154     flags = get_float_exception_flags(&env->fp_status);
    155     update_fpu_flags(env, flags, GETPC());
    156     return fd.l;
    157 }
    158 
    159 uint32_t helper_frsub(CPUMBState *env, uint32_t a, uint32_t b)
    160 {
    161     CPU_FloatU fd, fa, fb;
    162     int flags;
    163 
    164     set_float_exception_flags(0, &env->fp_status);
    165     fa.l = a;
    166     fb.l = b;
    167     fd.f = float32_sub(fb.f, fa.f, &env->fp_status);
    168     flags = get_float_exception_flags(&env->fp_status);
    169     update_fpu_flags(env, flags, GETPC());
    170     return fd.l;
    171 }
    172 
    173 uint32_t helper_fmul(CPUMBState *env, uint32_t a, uint32_t b)
    174 {
    175     CPU_FloatU fd, fa, fb;
    176     int flags;
    177 
    178     set_float_exception_flags(0, &env->fp_status);
    179     fa.l = a;
    180     fb.l = b;
    181     fd.f = float32_mul(fa.f, fb.f, &env->fp_status);
    182     flags = get_float_exception_flags(&env->fp_status);
    183     update_fpu_flags(env, flags, GETPC());
    184 
    185     return fd.l;
    186 }
    187 
    188 uint32_t helper_fdiv(CPUMBState *env, uint32_t a, uint32_t b)
    189 {
    190     CPU_FloatU fd, fa, fb;
    191     int flags;
    192 
    193     set_float_exception_flags(0, &env->fp_status);
    194     fa.l = a;
    195     fb.l = b;
    196     fd.f = float32_div(fb.f, fa.f, &env->fp_status);
    197     flags = get_float_exception_flags(&env->fp_status);
    198     update_fpu_flags(env, flags, GETPC());
    199 
    200     return fd.l;
    201 }
    202 
    203 uint32_t helper_fcmp_un(CPUMBState *env, uint32_t a, uint32_t b)
    204 {
    205     CPU_FloatU fa, fb;
    206     uint32_t r = 0;
    207 
    208     fa.l = a;
    209     fb.l = b;
    210 
    211     if (float32_is_signaling_nan(fa.f, &env->fp_status) ||
    212         float32_is_signaling_nan(fb.f, &env->fp_status)) {
    213         update_fpu_flags(env, float_flag_invalid, GETPC());
    214         r = 1;
    215     }
    216 
    217     if (float32_is_quiet_nan(fa.f, &env->fp_status) ||
    218         float32_is_quiet_nan(fb.f, &env->fp_status)) {
    219         r = 1;
    220     }
    221 
    222     return r;
    223 }
    224 
    225 uint32_t helper_fcmp_lt(CPUMBState *env, uint32_t a, uint32_t b)
    226 {
    227     CPU_FloatU fa, fb;
    228     int r;
    229     int flags;
    230 
    231     set_float_exception_flags(0, &env->fp_status);
    232     fa.l = a;
    233     fb.l = b;
    234     r = float32_lt(fb.f, fa.f, &env->fp_status);
    235     flags = get_float_exception_flags(&env->fp_status);
    236     update_fpu_flags(env, flags & float_flag_invalid, GETPC());
    237 
    238     return r;
    239 }
    240 
    241 uint32_t helper_fcmp_eq(CPUMBState *env, uint32_t a, uint32_t b)
    242 {
    243     CPU_FloatU fa, fb;
    244     int flags;
    245     int r;
    246 
    247     set_float_exception_flags(0, &env->fp_status);
    248     fa.l = a;
    249     fb.l = b;
    250     r = float32_eq_quiet(fa.f, fb.f, &env->fp_status);
    251     flags = get_float_exception_flags(&env->fp_status);
    252     update_fpu_flags(env, flags & float_flag_invalid, GETPC());
    253 
    254     return r;
    255 }
    256 
    257 uint32_t helper_fcmp_le(CPUMBState *env, uint32_t a, uint32_t b)
    258 {
    259     CPU_FloatU fa, fb;
    260     int flags;
    261     int r;
    262 
    263     fa.l = a;
    264     fb.l = b;
    265     set_float_exception_flags(0, &env->fp_status);
    266     r = float32_le(fa.f, fb.f, &env->fp_status);
    267     flags = get_float_exception_flags(&env->fp_status);
    268     update_fpu_flags(env, flags & float_flag_invalid, GETPC());
    269 
    270 
    271     return r;
    272 }
    273 
    274 uint32_t helper_fcmp_gt(CPUMBState *env, uint32_t a, uint32_t b)
    275 {
    276     CPU_FloatU fa, fb;
    277     int flags, r;
    278 
    279     fa.l = a;
    280     fb.l = b;
    281     set_float_exception_flags(0, &env->fp_status);
    282     r = float32_lt(fa.f, fb.f, &env->fp_status);
    283     flags = get_float_exception_flags(&env->fp_status);
    284     update_fpu_flags(env, flags & float_flag_invalid, GETPC());
    285     return r;
    286 }
    287 
    288 uint32_t helper_fcmp_ne(CPUMBState *env, uint32_t a, uint32_t b)
    289 {
    290     CPU_FloatU fa, fb;
    291     int flags, r;
    292 
    293     fa.l = a;
    294     fb.l = b;
    295     set_float_exception_flags(0, &env->fp_status);
    296     r = !float32_eq_quiet(fa.f, fb.f, &env->fp_status);
    297     flags = get_float_exception_flags(&env->fp_status);
    298     update_fpu_flags(env, flags & float_flag_invalid, GETPC());
    299 
    300     return r;
    301 }
    302 
    303 uint32_t helper_fcmp_ge(CPUMBState *env, uint32_t a, uint32_t b)
    304 {
    305     CPU_FloatU fa, fb;
    306     int flags, r;
    307 
    308     fa.l = a;
    309     fb.l = b;
    310     set_float_exception_flags(0, &env->fp_status);
    311     r = !float32_lt(fa.f, fb.f, &env->fp_status);
    312     flags = get_float_exception_flags(&env->fp_status);
    313     update_fpu_flags(env, flags & float_flag_invalid, GETPC());
    314 
    315     return r;
    316 }
    317 
    318 uint32_t helper_flt(CPUMBState *env, uint32_t a)
    319 {
    320     CPU_FloatU fd, fa;
    321 
    322     fa.l = a;
    323     fd.f = int32_to_float32(fa.l, &env->fp_status);
    324     return fd.l;
    325 }
    326 
    327 uint32_t helper_fint(CPUMBState *env, uint32_t a)
    328 {
    329     CPU_FloatU fa;
    330     uint32_t r;
    331     int flags;
    332 
    333     set_float_exception_flags(0, &env->fp_status);
    334     fa.l = a;
    335     r = float32_to_int32(fa.f, &env->fp_status);
    336     flags = get_float_exception_flags(&env->fp_status);
    337     update_fpu_flags(env, flags, GETPC());
    338 
    339     return r;
    340 }
    341 
    342 uint32_t helper_fsqrt(CPUMBState *env, uint32_t a)
    343 {
    344     CPU_FloatU fd, fa;
    345     int flags;
    346 
    347     set_float_exception_flags(0, &env->fp_status);
    348     fa.l = a;
    349     fd.l = float32_sqrt(fa.f, &env->fp_status);
    350     flags = get_float_exception_flags(&env->fp_status);
    351     update_fpu_flags(env, flags, GETPC());
    352 
    353     return fd.l;
    354 }
    355 
    356 uint32_t helper_pcmpbf(uint32_t a, uint32_t b)
    357 {
    358     unsigned int i;
    359     uint32_t mask = 0xff000000;
    360 
    361     for (i = 0; i < 4; i++) {
    362         if ((a & mask) == (b & mask))
    363             return i + 1;
    364         mask >>= 8;
    365     }
    366     return 0;
    367 }
    368 
    369 void helper_stackprot(CPUMBState *env, target_ulong addr)
    370 {
    371     if (addr < env->slr || addr > env->shr) {
    372         CPUState *cs = env_cpu(env);
    373 
    374         qemu_log_mask(CPU_LOG_INT, "Stack protector violation at "
    375                       TARGET_FMT_lx " %x %x\n",
    376                       addr, env->slr, env->shr);
    377 
    378         env->ear = addr;
    379         env->esr = ESR_EC_STACKPROT;
    380         cs->exception_index = EXCP_HW_EXCP;
    381         cpu_loop_exit_restore(cs, GETPC());
    382     }
    383 }
    384 
    385 #if !defined(CONFIG_USER_ONLY)
    386 /* Writes/reads to the MMU's special regs end up here.  */
    387 uint32_t helper_mmu_read(CPUMBState *env, uint32_t ext, uint32_t rn)
    388 {
    389     return mmu_read(env, ext, rn);
    390 }
    391 
    392 void helper_mmu_write(CPUMBState *env, uint32_t ext, uint32_t rn, uint32_t v)
    393 {
    394     mmu_write(env, ext, rn, v);
    395 }
    396 
    397 void mb_cpu_transaction_failed(CPUState *cs, hwaddr physaddr, vaddr addr,
    398                                unsigned size, MMUAccessType access_type,
    399                                int mmu_idx, MemTxAttrs attrs,
    400                                MemTxResult response, uintptr_t retaddr)
    401 {
    402     MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
    403     CPUMBState *env = &cpu->env;
    404 
    405     qemu_log_mask(CPU_LOG_INT, "Transaction failed: vaddr 0x%" VADDR_PRIx
    406                   " physaddr 0x" TARGET_FMT_plx " size %d access type %s\n",
    407                   addr, physaddr, size,
    408                   access_type == MMU_INST_FETCH ? "INST_FETCH" :
    409                   (access_type == MMU_DATA_LOAD ? "DATA_LOAD" : "DATA_STORE"));
    410 
    411     if (!(env->msr & MSR_EE)) {
    412         return;
    413     }
    414 
    415     if (access_type == MMU_INST_FETCH) {
    416         if (!cpu->cfg.iopb_bus_exception) {
    417             return;
    418         }
    419         env->esr = ESR_EC_INSN_BUS;
    420     } else {
    421         if (!cpu->cfg.dopb_bus_exception) {
    422             return;
    423         }
    424         env->esr = ESR_EC_DATA_BUS;
    425     }
    426 
    427     env->ear = addr;
    428     cs->exception_index = EXCP_HW_EXCP;
    429     cpu_loop_exit_restore(cs, retaddr);
    430 }
    431 #endif