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