qemu/target-sh4/op_helper.c
<<
>>
Prefs
   1/*
   2 *  SH4 emulation
   3 *
   4 *  Copyright (c) 2005 Samuel Tardieu
   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 <assert.h>
  20#include <stdlib.h>
  21#include "cpu.h"
  22#include "dyngen-exec.h"
  23#include "helper.h"
  24
  25static void cpu_restore_state_from_retaddr(uintptr_t retaddr)
  26{
  27    TranslationBlock *tb;
  28
  29    if (retaddr) {
  30        tb = tb_find_pc(retaddr);
  31        if (tb) {
  32            /* the PC is inside the translated code. It means that we have
  33               a virtual CPU fault */
  34            cpu_restore_state(tb, env, retaddr);
  35        }
  36    }
  37}
  38
  39#ifndef CONFIG_USER_ONLY
  40#include "softmmu_exec.h"
  41
  42#define MMUSUFFIX _mmu
  43
  44#define SHIFT 0
  45#include "softmmu_template.h"
  46
  47#define SHIFT 1
  48#include "softmmu_template.h"
  49
  50#define SHIFT 2
  51#include "softmmu_template.h"
  52
  53#define SHIFT 3
  54#include "softmmu_template.h"
  55
  56void tlb_fill(CPUSH4State *env1, target_ulong addr, int is_write, int mmu_idx,
  57              uintptr_t retaddr)
  58{
  59    CPUSH4State *saved_env;
  60    int ret;
  61
  62    saved_env = env;
  63    env = env1;
  64    ret = cpu_sh4_handle_mmu_fault(env, addr, is_write, mmu_idx);
  65    if (ret) {
  66        /* now we have a real cpu fault */
  67        cpu_restore_state_from_retaddr(retaddr);
  68        cpu_loop_exit(env);
  69    }
  70    env = saved_env;
  71}
  72
  73#endif
  74
  75void helper_ldtlb(void)
  76{
  77#ifdef CONFIG_USER_ONLY
  78    /* XXXXX */
  79    cpu_abort(env, "Unhandled ldtlb");
  80#else
  81    cpu_load_tlb(env);
  82#endif
  83}
  84
  85static inline void raise_exception(int index, uintptr_t retaddr)
  86{
  87    env->exception_index = index;
  88    cpu_restore_state_from_retaddr(retaddr);
  89    cpu_loop_exit(env);
  90}
  91
  92void helper_raise_illegal_instruction(void)
  93{
  94    raise_exception(0x180, GETPC());
  95}
  96
  97void helper_raise_slot_illegal_instruction(void)
  98{
  99    raise_exception(0x1a0, GETPC());
 100}
 101
 102void helper_raise_fpu_disable(void)
 103{
 104    raise_exception(0x800, GETPC());
 105}
 106
 107void helper_raise_slot_fpu_disable(void)
 108{
 109    raise_exception(0x820, GETPC());
 110}
 111
 112void helper_debug(void)
 113{
 114    env->exception_index = EXCP_DEBUG;
 115    cpu_loop_exit(env);
 116}
 117
 118void helper_sleep(uint32_t next_pc)
 119{
 120    env->halted = 1;
 121    env->in_sleep = 1;
 122    env->exception_index = EXCP_HLT;
 123    env->pc = next_pc;
 124    cpu_loop_exit(env);
 125}
 126
 127void helper_trapa(uint32_t tra)
 128{
 129    env->tra = tra << 2;
 130    raise_exception(0x160, GETPC());
 131}
 132
 133void helper_movcal(uint32_t address, uint32_t value)
 134{
 135    if (cpu_sh4_is_cached (env, address))
 136    {
 137        memory_content *r = malloc (sizeof(memory_content));
 138        r->address = address;
 139        r->value = value;
 140        r->next = NULL;
 141
 142        *(env->movcal_backup_tail) = r;
 143        env->movcal_backup_tail = &(r->next);
 144    }
 145}
 146
 147void helper_discard_movcal_backup(void)
 148{
 149    memory_content *current = env->movcal_backup;
 150
 151    while(current)
 152    {
 153        memory_content *next = current->next;
 154        free (current);
 155        env->movcal_backup = current = next;
 156        if (current == NULL)
 157            env->movcal_backup_tail = &(env->movcal_backup);
 158    } 
 159}
 160
 161void helper_ocbi(uint32_t address)
 162{
 163    memory_content **current = &(env->movcal_backup);
 164    while (*current)
 165    {
 166        uint32_t a = (*current)->address;
 167        if ((a & ~0x1F) == (address & ~0x1F))
 168        {
 169            memory_content *next = (*current)->next;
 170            stl(a, (*current)->value);
 171            
 172            if (next == NULL)
 173            {
 174                env->movcal_backup_tail = current;
 175            }
 176
 177            free (*current);
 178            *current = next;
 179            break;
 180        }
 181    }
 182}
 183
 184uint32_t helper_addc(uint32_t arg0, uint32_t arg1)
 185{
 186    uint32_t tmp0, tmp1;
 187
 188    tmp1 = arg0 + arg1;
 189    tmp0 = arg1;
 190    arg1 = tmp1 + (env->sr & 1);
 191    if (tmp0 > tmp1)
 192        env->sr |= SR_T;
 193    else
 194        env->sr &= ~SR_T;
 195    if (tmp1 > arg1)
 196        env->sr |= SR_T;
 197    return arg1;
 198}
 199
 200uint32_t helper_addv(uint32_t arg0, uint32_t arg1)
 201{
 202    uint32_t dest, src, ans;
 203
 204    if ((int32_t) arg1 >= 0)
 205        dest = 0;
 206    else
 207        dest = 1;
 208    if ((int32_t) arg0 >= 0)
 209        src = 0;
 210    else
 211        src = 1;
 212    src += dest;
 213    arg1 += arg0;
 214    if ((int32_t) arg1 >= 0)
 215        ans = 0;
 216    else
 217        ans = 1;
 218    ans += dest;
 219    if (src == 0 || src == 2) {
 220        if (ans == 1)
 221            env->sr |= SR_T;
 222        else
 223            env->sr &= ~SR_T;
 224    } else
 225        env->sr &= ~SR_T;
 226    return arg1;
 227}
 228
 229#define T (env->sr & SR_T)
 230#define Q (env->sr & SR_Q ? 1 : 0)
 231#define M (env->sr & SR_M ? 1 : 0)
 232#define SETT env->sr |= SR_T
 233#define CLRT env->sr &= ~SR_T
 234#define SETQ env->sr |= SR_Q
 235#define CLRQ env->sr &= ~SR_Q
 236#define SETM env->sr |= SR_M
 237#define CLRM env->sr &= ~SR_M
 238
 239uint32_t helper_div1(uint32_t arg0, uint32_t arg1)
 240{
 241    uint32_t tmp0, tmp2;
 242    uint8_t old_q, tmp1 = 0xff;
 243
 244    //printf("div1 arg0=0x%08x arg1=0x%08x M=%d Q=%d T=%d\n", arg0, arg1, M, Q, T);
 245    old_q = Q;
 246    if ((0x80000000 & arg1) != 0)
 247        SETQ;
 248    else
 249        CLRQ;
 250    tmp2 = arg0;
 251    arg1 <<= 1;
 252    arg1 |= T;
 253    switch (old_q) {
 254    case 0:
 255        switch (M) {
 256        case 0:
 257            tmp0 = arg1;
 258            arg1 -= tmp2;
 259            tmp1 = arg1 > tmp0;
 260            switch (Q) {
 261            case 0:
 262                if (tmp1)
 263                    SETQ;
 264                else
 265                    CLRQ;
 266                break;
 267            case 1:
 268                if (tmp1 == 0)
 269                    SETQ;
 270                else
 271                    CLRQ;
 272                break;
 273            }
 274            break;
 275        case 1:
 276            tmp0 = arg1;
 277            arg1 += tmp2;
 278            tmp1 = arg1 < tmp0;
 279            switch (Q) {
 280            case 0:
 281                if (tmp1 == 0)
 282                    SETQ;
 283                else
 284                    CLRQ;
 285                break;
 286            case 1:
 287                if (tmp1)
 288                    SETQ;
 289                else
 290                    CLRQ;
 291                break;
 292            }
 293            break;
 294        }
 295        break;
 296    case 1:
 297        switch (M) {
 298        case 0:
 299            tmp0 = arg1;
 300            arg1 += tmp2;
 301            tmp1 = arg1 < tmp0;
 302            switch (Q) {
 303            case 0:
 304                if (tmp1)
 305                    SETQ;
 306                else
 307                    CLRQ;
 308                break;
 309            case 1:
 310                if (tmp1 == 0)
 311                    SETQ;
 312                else
 313                    CLRQ;
 314                break;
 315            }
 316            break;
 317        case 1:
 318            tmp0 = arg1;
 319            arg1 -= tmp2;
 320            tmp1 = arg1 > tmp0;
 321            switch (Q) {
 322            case 0:
 323                if (tmp1 == 0)
 324                    SETQ;
 325                else
 326                    CLRQ;
 327                break;
 328            case 1:
 329                if (tmp1)
 330                    SETQ;
 331                else
 332                    CLRQ;
 333                break;
 334            }
 335            break;
 336        }
 337        break;
 338    }
 339    if (Q == M)
 340        SETT;
 341    else
 342        CLRT;
 343    //printf("Output: arg1=0x%08x M=%d Q=%d T=%d\n", arg1, M, Q, T);
 344    return arg1;
 345}
 346
 347void helper_macl(uint32_t arg0, uint32_t arg1)
 348{
 349    int64_t res;
 350
 351    res = ((uint64_t) env->mach << 32) | env->macl;
 352    res += (int64_t) (int32_t) arg0 *(int64_t) (int32_t) arg1;
 353    env->mach = (res >> 32) & 0xffffffff;
 354    env->macl = res & 0xffffffff;
 355    if (env->sr & SR_S) {
 356        if (res < 0)
 357            env->mach |= 0xffff0000;
 358        else
 359            env->mach &= 0x00007fff;
 360    }
 361}
 362
 363void helper_macw(uint32_t arg0, uint32_t arg1)
 364{
 365    int64_t res;
 366
 367    res = ((uint64_t) env->mach << 32) | env->macl;
 368    res += (int64_t) (int16_t) arg0 *(int64_t) (int16_t) arg1;
 369    env->mach = (res >> 32) & 0xffffffff;
 370    env->macl = res & 0xffffffff;
 371    if (env->sr & SR_S) {
 372        if (res < -0x80000000) {
 373            env->mach = 1;
 374            env->macl = 0x80000000;
 375        } else if (res > 0x000000007fffffff) {
 376            env->mach = 1;
 377            env->macl = 0x7fffffff;
 378        }
 379    }
 380}
 381
 382uint32_t helper_subc(uint32_t arg0, uint32_t arg1)
 383{
 384    uint32_t tmp0, tmp1;
 385
 386    tmp1 = arg1 - arg0;
 387    tmp0 = arg1;
 388    arg1 = tmp1 - (env->sr & SR_T);
 389    if (tmp0 < tmp1)
 390        env->sr |= SR_T;
 391    else
 392        env->sr &= ~SR_T;
 393    if (tmp1 < arg1)
 394        env->sr |= SR_T;
 395    return arg1;
 396}
 397
 398uint32_t helper_subv(uint32_t arg0, uint32_t arg1)
 399{
 400    int32_t dest, src, ans;
 401
 402    if ((int32_t) arg1 >= 0)
 403        dest = 0;
 404    else
 405        dest = 1;
 406    if ((int32_t) arg0 >= 0)
 407        src = 0;
 408    else
 409        src = 1;
 410    src += dest;
 411    arg1 -= arg0;
 412    if ((int32_t) arg1 >= 0)
 413        ans = 0;
 414    else
 415        ans = 1;
 416    ans += dest;
 417    if (src == 1) {
 418        if (ans == 1)
 419            env->sr |= SR_T;
 420        else
 421            env->sr &= ~SR_T;
 422    } else
 423        env->sr &= ~SR_T;
 424    return arg1;
 425}
 426
 427static inline void set_t(void)
 428{
 429    env->sr |= SR_T;
 430}
 431
 432static inline void clr_t(void)
 433{
 434    env->sr &= ~SR_T;
 435}
 436
 437void helper_ld_fpscr(uint32_t val)
 438{
 439    env->fpscr = val & FPSCR_MASK;
 440    if ((val & FPSCR_RM_MASK) == FPSCR_RM_ZERO) {
 441        set_float_rounding_mode(float_round_to_zero, &env->fp_status);
 442    } else {
 443        set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
 444    }
 445    set_flush_to_zero((val & FPSCR_DN) != 0, &env->fp_status);
 446}
 447
 448static void update_fpscr(uintptr_t retaddr)
 449{
 450    int xcpt, cause, enable;
 451
 452    xcpt = get_float_exception_flags(&env->fp_status);
 453
 454    /* Clear the flag entries */
 455    env->fpscr &= ~FPSCR_FLAG_MASK;
 456
 457    if (unlikely(xcpt)) {
 458        if (xcpt & float_flag_invalid) {
 459            env->fpscr |= FPSCR_FLAG_V;
 460        }
 461        if (xcpt & float_flag_divbyzero) {
 462            env->fpscr |= FPSCR_FLAG_Z;
 463        }
 464        if (xcpt & float_flag_overflow) {
 465            env->fpscr |= FPSCR_FLAG_O;
 466        }
 467        if (xcpt & float_flag_underflow) {
 468            env->fpscr |= FPSCR_FLAG_U;
 469        }
 470        if (xcpt & float_flag_inexact) {
 471            env->fpscr |= FPSCR_FLAG_I;
 472        }
 473
 474        /* Accumulate in cause entries */
 475        env->fpscr |= (env->fpscr & FPSCR_FLAG_MASK)
 476                      << (FPSCR_CAUSE_SHIFT - FPSCR_FLAG_SHIFT);
 477
 478        /* Generate an exception if enabled */
 479        cause = (env->fpscr & FPSCR_CAUSE_MASK) >> FPSCR_CAUSE_SHIFT;
 480        enable = (env->fpscr & FPSCR_ENABLE_MASK) >> FPSCR_ENABLE_SHIFT;
 481        if (cause & enable) {
 482            cpu_restore_state_from_retaddr(retaddr);
 483            env->exception_index = 0x120;
 484            cpu_loop_exit(env);
 485        }
 486    }
 487}
 488
 489float32 helper_fabs_FT(float32 t0)
 490{
 491    return float32_abs(t0);
 492}
 493
 494float64 helper_fabs_DT(float64 t0)
 495{
 496    return float64_abs(t0);
 497}
 498
 499float32 helper_fadd_FT(float32 t0, float32 t1)
 500{
 501    set_float_exception_flags(0, &env->fp_status);
 502    t0 = float32_add(t0, t1, &env->fp_status);
 503    update_fpscr(GETPC());
 504    return t0;
 505}
 506
 507float64 helper_fadd_DT(float64 t0, float64 t1)
 508{
 509    set_float_exception_flags(0, &env->fp_status);
 510    t0 = float64_add(t0, t1, &env->fp_status);
 511    update_fpscr(GETPC());
 512    return t0;
 513}
 514
 515void helper_fcmp_eq_FT(float32 t0, float32 t1)
 516{
 517    int relation;
 518
 519    set_float_exception_flags(0, &env->fp_status);
 520    relation = float32_compare(t0, t1, &env->fp_status);
 521    if (unlikely(relation == float_relation_unordered)) {
 522        update_fpscr(GETPC());
 523    } else if (relation == float_relation_equal) {
 524        set_t();
 525    } else {
 526        clr_t();
 527    }
 528}
 529
 530void helper_fcmp_eq_DT(float64 t0, float64 t1)
 531{
 532    int relation;
 533
 534    set_float_exception_flags(0, &env->fp_status);
 535    relation = float64_compare(t0, t1, &env->fp_status);
 536    if (unlikely(relation == float_relation_unordered)) {
 537        update_fpscr(GETPC());
 538    } else if (relation == float_relation_equal) {
 539        set_t();
 540    } else {
 541        clr_t();
 542    }
 543}
 544
 545void helper_fcmp_gt_FT(float32 t0, float32 t1)
 546{
 547    int relation;
 548
 549    set_float_exception_flags(0, &env->fp_status);
 550    relation = float32_compare(t0, t1, &env->fp_status);
 551    if (unlikely(relation == float_relation_unordered)) {
 552        update_fpscr(GETPC());
 553    } else if (relation == float_relation_greater) {
 554        set_t();
 555    } else {
 556        clr_t();
 557    }
 558}
 559
 560void helper_fcmp_gt_DT(float64 t0, float64 t1)
 561{
 562    int relation;
 563
 564    set_float_exception_flags(0, &env->fp_status);
 565    relation = float64_compare(t0, t1, &env->fp_status);
 566    if (unlikely(relation == float_relation_unordered)) {
 567        update_fpscr(GETPC());
 568    } else if (relation == float_relation_greater) {
 569        set_t();
 570    } else {
 571        clr_t();
 572    }
 573}
 574
 575float64 helper_fcnvsd_FT_DT(float32 t0)
 576{
 577    float64 ret;
 578    set_float_exception_flags(0, &env->fp_status);
 579    ret = float32_to_float64(t0, &env->fp_status);
 580    update_fpscr(GETPC());
 581    return ret;
 582}
 583
 584float32 helper_fcnvds_DT_FT(float64 t0)
 585{
 586    float32 ret;
 587    set_float_exception_flags(0, &env->fp_status);
 588    ret = float64_to_float32(t0, &env->fp_status);
 589    update_fpscr(GETPC());
 590    return ret;
 591}
 592
 593float32 helper_fdiv_FT(float32 t0, float32 t1)
 594{
 595    set_float_exception_flags(0, &env->fp_status);
 596    t0 = float32_div(t0, t1, &env->fp_status);
 597    update_fpscr(GETPC());
 598    return t0;
 599}
 600
 601float64 helper_fdiv_DT(float64 t0, float64 t1)
 602{
 603    set_float_exception_flags(0, &env->fp_status);
 604    t0 = float64_div(t0, t1, &env->fp_status);
 605    update_fpscr(GETPC());
 606    return t0;
 607}
 608
 609float32 helper_float_FT(uint32_t t0)
 610{
 611    float32 ret;
 612    set_float_exception_flags(0, &env->fp_status);
 613    ret = int32_to_float32(t0, &env->fp_status);
 614    update_fpscr(GETPC());
 615    return ret;
 616}
 617
 618float64 helper_float_DT(uint32_t t0)
 619{
 620    float64 ret;
 621    set_float_exception_flags(0, &env->fp_status);
 622    ret = int32_to_float64(t0, &env->fp_status);
 623    update_fpscr(GETPC());
 624    return ret;
 625}
 626
 627float32 helper_fmac_FT(float32 t0, float32 t1, float32 t2)
 628{
 629    set_float_exception_flags(0, &env->fp_status);
 630    t0 = float32_mul(t0, t1, &env->fp_status);
 631    t0 = float32_add(t0, t2, &env->fp_status);
 632    update_fpscr(GETPC());
 633    return t0;
 634}
 635
 636float32 helper_fmul_FT(float32 t0, float32 t1)
 637{
 638    set_float_exception_flags(0, &env->fp_status);
 639    t0 = float32_mul(t0, t1, &env->fp_status);
 640    update_fpscr(GETPC());
 641    return t0;
 642}
 643
 644float64 helper_fmul_DT(float64 t0, float64 t1)
 645{
 646    set_float_exception_flags(0, &env->fp_status);
 647    t0 = float64_mul(t0, t1, &env->fp_status);
 648    update_fpscr(GETPC());
 649    return t0;
 650}
 651
 652float32 helper_fneg_T(float32 t0)
 653{
 654    return float32_chs(t0);
 655}
 656
 657float32 helper_fsqrt_FT(float32 t0)
 658{
 659    set_float_exception_flags(0, &env->fp_status);
 660    t0 = float32_sqrt(t0, &env->fp_status);
 661    update_fpscr(GETPC());
 662    return t0;
 663}
 664
 665float64 helper_fsqrt_DT(float64 t0)
 666{
 667    set_float_exception_flags(0, &env->fp_status);
 668    t0 = float64_sqrt(t0, &env->fp_status);
 669    update_fpscr(GETPC());
 670    return t0;
 671}
 672
 673float32 helper_fsub_FT(float32 t0, float32 t1)
 674{
 675    set_float_exception_flags(0, &env->fp_status);
 676    t0 = float32_sub(t0, t1, &env->fp_status);
 677    update_fpscr(GETPC());
 678    return t0;
 679}
 680
 681float64 helper_fsub_DT(float64 t0, float64 t1)
 682{
 683    set_float_exception_flags(0, &env->fp_status);
 684    t0 = float64_sub(t0, t1, &env->fp_status);
 685    update_fpscr(GETPC());
 686    return t0;
 687}
 688
 689uint32_t helper_ftrc_FT(float32 t0)
 690{
 691    uint32_t ret;
 692    set_float_exception_flags(0, &env->fp_status);
 693    ret = float32_to_int32_round_to_zero(t0, &env->fp_status);
 694    update_fpscr(GETPC());
 695    return ret;
 696}
 697
 698uint32_t helper_ftrc_DT(float64 t0)
 699{
 700    uint32_t ret;
 701    set_float_exception_flags(0, &env->fp_status);
 702    ret = float64_to_int32_round_to_zero(t0, &env->fp_status);
 703    update_fpscr(GETPC());
 704    return ret;
 705}
 706
 707void helper_fipr(uint32_t m, uint32_t n)
 708{
 709    int bank, i;
 710    float32 r, p;
 711
 712    bank = (env->sr & FPSCR_FR) ? 16 : 0;
 713    r = float32_zero;
 714    set_float_exception_flags(0, &env->fp_status);
 715
 716    for (i = 0 ; i < 4 ; i++) {
 717        p = float32_mul(env->fregs[bank + m + i],
 718                        env->fregs[bank + n + i],
 719                        &env->fp_status);
 720        r = float32_add(r, p, &env->fp_status);
 721    }
 722    update_fpscr(GETPC());
 723
 724    env->fregs[bank + n + 3] = r;
 725}
 726
 727void helper_ftrv(uint32_t n)
 728{
 729    int bank_matrix, bank_vector;
 730    int i, j;
 731    float32 r[4];
 732    float32 p;
 733
 734    bank_matrix = (env->sr & FPSCR_FR) ? 0 : 16;
 735    bank_vector = (env->sr & FPSCR_FR) ? 16 : 0;
 736    set_float_exception_flags(0, &env->fp_status);
 737    for (i = 0 ; i < 4 ; i++) {
 738        r[i] = float32_zero;
 739        for (j = 0 ; j < 4 ; j++) {
 740            p = float32_mul(env->fregs[bank_matrix + 4 * j + i],
 741                            env->fregs[bank_vector + j],
 742                            &env->fp_status);
 743            r[i] = float32_add(r[i], p, &env->fp_status);
 744        }
 745    }
 746    update_fpscr(GETPC());
 747
 748    for (i = 0 ; i < 4 ; i++) {
 749        env->fregs[bank_vector + i] = r[i];
 750    }
 751}
 752