qemu/target-microblaze/op_helper.c
<<
>>
Prefs
   1/*
   2 *  Microblaze helper routines.
   3 *
   4 *  Copyright (c) 2009 Edgar E. Iglesias <edgar.iglesias@gmail.com>.
   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
  20#include <assert.h>
  21#include "cpu.h"
  22#include "dyngen-exec.h"
  23#include "helper.h"
  24#include "host-utils.h"
  25
  26#define D(x)
  27
  28#if !defined(CONFIG_USER_ONLY)
  29#include "softmmu_exec.h"
  30
  31#define MMUSUFFIX _mmu
  32#define SHIFT 0
  33#include "softmmu_template.h"
  34#define SHIFT 1
  35#include "softmmu_template.h"
  36#define SHIFT 2
  37#include "softmmu_template.h"
  38#define SHIFT 3
  39#include "softmmu_template.h"
  40
  41/* Try to fill the TLB and return an exception if error. If retaddr is
  42   NULL, it means that the function was called in C code (i.e. not
  43   from generated code or from helper.c) */
  44/* XXX: fix it to restore all registers */
  45void tlb_fill(CPUState *env1, target_ulong addr, int is_write, int mmu_idx,
  46              void *retaddr)
  47{
  48    TranslationBlock *tb;
  49    CPUState *saved_env;
  50    unsigned long pc;
  51    int ret;
  52
  53    saved_env = env;
  54    env = env1;
  55
  56    ret = cpu_mb_handle_mmu_fault(env, addr, is_write, mmu_idx);
  57    if (unlikely(ret)) {
  58        if (retaddr) {
  59            /* now we have a real cpu fault */
  60            pc = (unsigned long)retaddr;
  61            tb = tb_find_pc(pc);
  62            if (tb) {
  63                /* the PC is inside the translated code. It means that we have
  64                   a virtual CPU fault */
  65                cpu_restore_state(tb, env, pc);
  66            }
  67        }
  68        cpu_loop_exit(env);
  69    }
  70    env = saved_env;
  71}
  72#endif
  73
  74void helper_put(uint32_t id, uint32_t ctrl, uint32_t data)
  75{
  76    int test = ctrl & STREAM_TEST;
  77    int atomic = ctrl & STREAM_ATOMIC;
  78    int control = ctrl & STREAM_CONTROL;
  79    int nonblock = ctrl & STREAM_NONBLOCK;
  80    int exception = ctrl & STREAM_EXCEPTION;
  81
  82    qemu_log("Unhandled stream put to stream-id=%d data=%x %s%s%s%s%s\n",
  83             id, data,
  84             test ? "t" : "",
  85             nonblock ? "n" : "",
  86             exception ? "e" : "",
  87             control ? "c" : "",
  88             atomic ? "a" : "");
  89}
  90
  91uint32_t helper_get(uint32_t id, uint32_t ctrl)
  92{
  93    int test = ctrl & STREAM_TEST;
  94    int atomic = ctrl & STREAM_ATOMIC;
  95    int control = ctrl & STREAM_CONTROL;
  96    int nonblock = ctrl & STREAM_NONBLOCK;
  97    int exception = ctrl & STREAM_EXCEPTION;
  98
  99    qemu_log("Unhandled stream get from stream-id=%d %s%s%s%s%s\n",
 100             id,
 101             test ? "t" : "",
 102             nonblock ? "n" : "",
 103             exception ? "e" : "",
 104             control ? "c" : "",
 105             atomic ? "a" : "");
 106    return 0xdead0000 | id;
 107}
 108
 109void helper_raise_exception(uint32_t index)
 110{
 111    env->exception_index = index;
 112    cpu_loop_exit(env);
 113}
 114
 115void helper_debug(void)
 116{
 117    int i;
 118
 119    qemu_log("PC=%8.8x\n", env->sregs[SR_PC]);
 120    qemu_log("rmsr=%x resr=%x rear=%x debug[%x] imm=%x iflags=%x\n",
 121             env->sregs[SR_MSR], env->sregs[SR_ESR], env->sregs[SR_EAR],
 122             env->debug, env->imm, env->iflags);
 123    qemu_log("btaken=%d btarget=%x mode=%s(saved=%s) eip=%d ie=%d\n",
 124             env->btaken, env->btarget,
 125             (env->sregs[SR_MSR] & MSR_UM) ? "user" : "kernel",
 126             (env->sregs[SR_MSR] & MSR_UMS) ? "user" : "kernel",
 127             (env->sregs[SR_MSR] & MSR_EIP),
 128             (env->sregs[SR_MSR] & MSR_IE));
 129    for (i = 0; i < 32; i++) {
 130        qemu_log("r%2.2d=%8.8x ", i, env->regs[i]);
 131        if ((i + 1) % 4 == 0)
 132            qemu_log("\n");
 133    }
 134    qemu_log("\n\n");
 135}
 136
 137static inline uint32_t compute_carry(uint32_t a, uint32_t b, uint32_t cin)
 138{
 139    uint32_t cout = 0;
 140
 141    if ((b == ~0) && cin)
 142        cout = 1;
 143    else if ((~0 - a) < (b + cin))
 144        cout = 1;
 145    return cout;
 146}
 147
 148uint32_t helper_cmp(uint32_t a, uint32_t b)
 149{
 150    uint32_t t;
 151
 152    t = b + ~a + 1;
 153    if ((b & 0x80000000) ^ (a & 0x80000000))
 154        t = (t & 0x7fffffff) | (b & 0x80000000);
 155    return t;
 156}
 157
 158uint32_t helper_cmpu(uint32_t a, uint32_t b)
 159{
 160    uint32_t t;
 161
 162    t = b + ~a + 1;
 163    if ((b & 0x80000000) ^ (a & 0x80000000))
 164        t = (t & 0x7fffffff) | (a & 0x80000000);
 165    return t;
 166}
 167
 168uint32_t helper_carry(uint32_t a, uint32_t b, uint32_t cf)
 169{
 170    uint32_t ncf;
 171    ncf = compute_carry(a, b, cf);
 172    return ncf;
 173}
 174
 175static inline int div_prepare(uint32_t a, uint32_t b)
 176{
 177    if (b == 0) {
 178        env->sregs[SR_MSR] |= MSR_DZ;
 179
 180        if ((env->sregs[SR_MSR] & MSR_EE)
 181            && !(env->pvr.regs[2] & PVR2_DIV_ZERO_EXC_MASK)) {
 182            env->sregs[SR_ESR] = ESR_EC_DIVZERO;
 183            helper_raise_exception(EXCP_HW_EXCP);
 184        }
 185        return 0;
 186    }
 187    env->sregs[SR_MSR] &= ~MSR_DZ;
 188    return 1;
 189}
 190
 191uint32_t helper_divs(uint32_t a, uint32_t b)
 192{
 193    if (!div_prepare(a, b))
 194        return 0;
 195    return (int32_t)a / (int32_t)b;
 196}
 197
 198uint32_t helper_divu(uint32_t a, uint32_t b)
 199{
 200    if (!div_prepare(a, b))
 201        return 0;
 202    return a / b;
 203}
 204
 205/* raise FPU exception.  */
 206static void raise_fpu_exception(void)
 207{
 208    env->sregs[SR_ESR] = ESR_EC_FPU;
 209    helper_raise_exception(EXCP_HW_EXCP);
 210}
 211
 212static void update_fpu_flags(int flags)
 213{
 214    int raise = 0;
 215
 216    if (flags & float_flag_invalid) {
 217        env->sregs[SR_FSR] |= FSR_IO;
 218        raise = 1;
 219    }
 220    if (flags & float_flag_divbyzero) {
 221        env->sregs[SR_FSR] |= FSR_DZ;
 222        raise = 1;
 223    }
 224    if (flags & float_flag_overflow) {
 225        env->sregs[SR_FSR] |= FSR_OF;
 226        raise = 1;
 227    }
 228    if (flags & float_flag_underflow) {
 229        env->sregs[SR_FSR] |= FSR_UF;
 230        raise = 1;
 231    }
 232    if (raise
 233        && (env->pvr.regs[2] & PVR2_FPU_EXC_MASK)
 234        && (env->sregs[SR_MSR] & MSR_EE)) {
 235        raise_fpu_exception();
 236    }
 237}
 238
 239uint32_t helper_fadd(uint32_t a, uint32_t b)
 240{
 241    CPU_FloatU fd, fa, fb;
 242    int flags;
 243
 244    set_float_exception_flags(0, &env->fp_status);
 245    fa.l = a;
 246    fb.l = b;
 247    fd.f = float32_add(fa.f, fb.f, &env->fp_status);
 248
 249    flags = get_float_exception_flags(&env->fp_status);
 250    update_fpu_flags(flags);
 251    return fd.l;
 252}
 253
 254uint32_t helper_frsub(uint32_t a, uint32_t b)
 255{
 256    CPU_FloatU fd, fa, fb;
 257    int flags;
 258
 259    set_float_exception_flags(0, &env->fp_status);
 260    fa.l = a;
 261    fb.l = b;
 262    fd.f = float32_sub(fb.f, fa.f, &env->fp_status);
 263    flags = get_float_exception_flags(&env->fp_status);
 264    update_fpu_flags(flags);
 265    return fd.l;
 266}
 267
 268uint32_t helper_fmul(uint32_t a, uint32_t b)
 269{
 270    CPU_FloatU fd, fa, fb;
 271    int flags;
 272
 273    set_float_exception_flags(0, &env->fp_status);
 274    fa.l = a;
 275    fb.l = b;
 276    fd.f = float32_mul(fa.f, fb.f, &env->fp_status);
 277    flags = get_float_exception_flags(&env->fp_status);
 278    update_fpu_flags(flags);
 279
 280    return fd.l;
 281}
 282
 283uint32_t helper_fdiv(uint32_t a, uint32_t b)
 284{
 285    CPU_FloatU fd, fa, fb;
 286    int flags;
 287
 288    set_float_exception_flags(0, &env->fp_status);
 289    fa.l = a;
 290    fb.l = b;
 291    fd.f = float32_div(fb.f, fa.f, &env->fp_status);
 292    flags = get_float_exception_flags(&env->fp_status);
 293    update_fpu_flags(flags);
 294
 295    return fd.l;
 296}
 297
 298uint32_t helper_fcmp_un(uint32_t a, uint32_t b)
 299{
 300    CPU_FloatU fa, fb;
 301    uint32_t r = 0;
 302
 303    fa.l = a;
 304    fb.l = b;
 305
 306    if (float32_is_signaling_nan(fa.f) || float32_is_signaling_nan(fb.f)) {
 307        update_fpu_flags(float_flag_invalid);
 308        r = 1;
 309    }
 310
 311    if (float32_is_quiet_nan(fa.f) || float32_is_quiet_nan(fb.f)) {
 312        r = 1;
 313    }
 314
 315    return r;
 316}
 317
 318uint32_t helper_fcmp_lt(uint32_t a, uint32_t b)
 319{
 320    CPU_FloatU fa, fb;
 321    int r;
 322    int flags;
 323
 324    set_float_exception_flags(0, &env->fp_status);
 325    fa.l = a;
 326    fb.l = b;
 327    r = float32_lt(fb.f, fa.f, &env->fp_status);
 328    flags = get_float_exception_flags(&env->fp_status);
 329    update_fpu_flags(flags & float_flag_invalid);
 330
 331    return r;
 332}
 333
 334uint32_t helper_fcmp_eq(uint32_t a, uint32_t b)
 335{
 336    CPU_FloatU fa, fb;
 337    int flags;
 338    int r;
 339
 340    set_float_exception_flags(0, &env->fp_status);
 341    fa.l = a;
 342    fb.l = b;
 343    r = float32_eq_quiet(fa.f, fb.f, &env->fp_status);
 344    flags = get_float_exception_flags(&env->fp_status);
 345    update_fpu_flags(flags & float_flag_invalid);
 346
 347    return r;
 348}
 349
 350uint32_t helper_fcmp_le(uint32_t a, uint32_t b)
 351{
 352    CPU_FloatU fa, fb;
 353    int flags;
 354    int r;
 355
 356    fa.l = a;
 357    fb.l = b;
 358    set_float_exception_flags(0, &env->fp_status);
 359    r = float32_le(fa.f, fb.f, &env->fp_status);
 360    flags = get_float_exception_flags(&env->fp_status);
 361    update_fpu_flags(flags & float_flag_invalid);
 362
 363
 364    return r;
 365}
 366
 367uint32_t helper_fcmp_gt(uint32_t a, uint32_t b)
 368{
 369    CPU_FloatU fa, fb;
 370    int flags, r;
 371
 372    fa.l = a;
 373    fb.l = b;
 374    set_float_exception_flags(0, &env->fp_status);
 375    r = float32_lt(fa.f, fb.f, &env->fp_status);
 376    flags = get_float_exception_flags(&env->fp_status);
 377    update_fpu_flags(flags & float_flag_invalid);
 378    return r;
 379}
 380
 381uint32_t helper_fcmp_ne(uint32_t a, uint32_t b)
 382{
 383    CPU_FloatU fa, fb;
 384    int flags, r;
 385
 386    fa.l = a;
 387    fb.l = b;
 388    set_float_exception_flags(0, &env->fp_status);
 389    r = !float32_eq_quiet(fa.f, fb.f, &env->fp_status);
 390    flags = get_float_exception_flags(&env->fp_status);
 391    update_fpu_flags(flags & float_flag_invalid);
 392
 393    return r;
 394}
 395
 396uint32_t helper_fcmp_ge(uint32_t a, uint32_t b)
 397{
 398    CPU_FloatU fa, fb;
 399    int flags, r;
 400
 401    fa.l = a;
 402    fb.l = b;
 403    set_float_exception_flags(0, &env->fp_status);
 404    r = !float32_lt(fa.f, fb.f, &env->fp_status);
 405    flags = get_float_exception_flags(&env->fp_status);
 406    update_fpu_flags(flags & float_flag_invalid);
 407
 408    return r;
 409}
 410
 411uint32_t helper_flt(uint32_t a)
 412{
 413    CPU_FloatU fd, fa;
 414
 415    fa.l = a;
 416    fd.f = int32_to_float32(fa.l, &env->fp_status);
 417    return fd.l;
 418}
 419
 420uint32_t helper_fint(uint32_t a)
 421{
 422    CPU_FloatU fa;
 423    uint32_t r;
 424    int flags;
 425
 426    set_float_exception_flags(0, &env->fp_status);
 427    fa.l = a;
 428    r = float32_to_int32(fa.f, &env->fp_status);
 429    flags = get_float_exception_flags(&env->fp_status);
 430    update_fpu_flags(flags);
 431
 432    return r;
 433}
 434
 435uint32_t helper_fsqrt(uint32_t a)
 436{
 437    CPU_FloatU fd, fa;
 438    int flags;
 439
 440    set_float_exception_flags(0, &env->fp_status);
 441    fa.l = a;
 442    fd.l = float32_sqrt(fa.f, &env->fp_status);
 443    flags = get_float_exception_flags(&env->fp_status);
 444    update_fpu_flags(flags);
 445
 446    return fd.l;
 447}
 448
 449uint32_t helper_pcmpbf(uint32_t a, uint32_t b)
 450{
 451    unsigned int i;
 452    uint32_t mask = 0xff000000;
 453
 454    for (i = 0; i < 4; i++) {
 455        if ((a & mask) == (b & mask))
 456            return i + 1;
 457        mask >>= 8;
 458    }
 459    return 0;
 460}
 461
 462void helper_memalign(uint32_t addr, uint32_t dr, uint32_t wr, uint32_t mask)
 463{
 464    if (addr & mask) {
 465            qemu_log_mask(CPU_LOG_INT,
 466                          "unaligned access addr=%x mask=%x, wr=%d dr=r%d\n",
 467                          addr, mask, wr, dr);
 468            env->sregs[SR_EAR] = addr;
 469            env->sregs[SR_ESR] = ESR_EC_UNALIGNED_DATA | (wr << 10) \
 470                                 | (dr & 31) << 5;
 471            if (mask == 3) {
 472                env->sregs[SR_ESR] |= 1 << 11;
 473            }
 474            if (!(env->sregs[SR_MSR] & MSR_EE)) {
 475                return;
 476            }
 477            helper_raise_exception(EXCP_HW_EXCP);
 478    }
 479}
 480
 481#if !defined(CONFIG_USER_ONLY)
 482/* Writes/reads to the MMU's special regs end up here.  */
 483uint32_t helper_mmu_read(uint32_t rn)
 484{
 485    return mmu_read(env, rn);
 486}
 487
 488void helper_mmu_write(uint32_t rn, uint32_t v)
 489{
 490    mmu_write(env, rn, v);
 491}
 492
 493void cpu_unassigned_access(CPUState *env1, target_phys_addr_t addr,
 494                           int is_write, int is_exec, int is_asi, int size)
 495{
 496    CPUState *saved_env;
 497
 498    saved_env = env;
 499    env = env1;
 500
 501    qemu_log_mask(CPU_LOG_INT, "Unassigned " TARGET_FMT_plx " wr=%d exe=%d\n",
 502             addr, is_write, is_exec);
 503    if (!(env->sregs[SR_MSR] & MSR_EE)) {
 504        env = saved_env;
 505        return;
 506    }
 507
 508    env->sregs[SR_EAR] = addr;
 509    if (is_exec) {
 510        if ((env->pvr.regs[2] & PVR2_IOPB_BUS_EXC_MASK)) {
 511            env->sregs[SR_ESR] = ESR_EC_INSN_BUS;
 512            helper_raise_exception(EXCP_HW_EXCP);
 513        }
 514    } else {
 515        if ((env->pvr.regs[2] & PVR2_DOPB_BUS_EXC_MASK)) {
 516            env->sregs[SR_ESR] = ESR_EC_DATA_BUS;
 517            helper_raise_exception(EXCP_HW_EXCP);
 518        }
 519    }
 520    env = saved_env;
 521}
 522#endif
 523