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.1 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 "qemu/osdep.h"
  20#include "cpu.h"
  21#include "exec/helper-proto.h"
  22#include "exec/exec-all.h"
  23#include "exec/cpu_ldst.h"
  24#include "fpu/softfloat.h"
  25
  26#ifndef CONFIG_USER_ONLY
  27
  28void superh_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
  29                                    MMUAccessType access_type,
  30                                    int mmu_idx, uintptr_t retaddr)
  31{
  32    CPUSH4State *env = cs->env_ptr;
  33
  34    env->tea = addr;
  35    switch (access_type) {
  36    case MMU_INST_FETCH:
  37    case MMU_DATA_LOAD:
  38        cs->exception_index = 0x0e0;
  39        break;
  40    case MMU_DATA_STORE:
  41        cs->exception_index = 0x100;
  42        break;
  43    default:
  44        g_assert_not_reached();
  45    }
  46    cpu_loop_exit_restore(cs, retaddr);
  47}
  48
  49#endif
  50
  51void helper_ldtlb(CPUSH4State *env)
  52{
  53#ifdef CONFIG_USER_ONLY
  54    cpu_abort(env_cpu(env), "Unhandled ldtlb");
  55#else
  56    cpu_load_tlb(env);
  57#endif
  58}
  59
  60static inline G_NORETURN
  61void raise_exception(CPUSH4State *env, int index,
  62                     uintptr_t retaddr)
  63{
  64    CPUState *cs = env_cpu(env);
  65
  66    cs->exception_index = index;
  67    cpu_loop_exit_restore(cs, retaddr);
  68}
  69
  70void helper_raise_illegal_instruction(CPUSH4State *env)
  71{
  72    raise_exception(env, 0x180, 0);
  73}
  74
  75void helper_raise_slot_illegal_instruction(CPUSH4State *env)
  76{
  77    raise_exception(env, 0x1a0, 0);
  78}
  79
  80void helper_raise_fpu_disable(CPUSH4State *env)
  81{
  82    raise_exception(env, 0x800, 0);
  83}
  84
  85void helper_raise_slot_fpu_disable(CPUSH4State *env)
  86{
  87    raise_exception(env, 0x820, 0);
  88}
  89
  90void helper_sleep(CPUSH4State *env)
  91{
  92    CPUState *cs = env_cpu(env);
  93
  94    cs->halted = 1;
  95    env->in_sleep = 1;
  96    raise_exception(env, EXCP_HLT, 0);
  97}
  98
  99void helper_trapa(CPUSH4State *env, uint32_t tra)
 100{
 101    env->tra = tra << 2;
 102    raise_exception(env, 0x160, 0);
 103}
 104
 105void helper_exclusive(CPUSH4State *env)
 106{
 107    /* We do not want cpu_restore_state to run.  */
 108    cpu_loop_exit_atomic(env_cpu(env), 0);
 109}
 110
 111void helper_movcal(CPUSH4State *env, uint32_t address, uint32_t value)
 112{
 113    if (cpu_sh4_is_cached (env, address))
 114    {
 115        memory_content *r = g_new(memory_content, 1);
 116
 117        r->address = address;
 118        r->value = value;
 119        r->next = NULL;
 120
 121        *(env->movcal_backup_tail) = r;
 122        env->movcal_backup_tail = &(r->next);
 123    }
 124}
 125
 126void helper_discard_movcal_backup(CPUSH4State *env)
 127{
 128    memory_content *current = env->movcal_backup;
 129
 130    while(current)
 131    {
 132        memory_content *next = current->next;
 133        g_free(current);
 134        env->movcal_backup = current = next;
 135        if (current == NULL)
 136            env->movcal_backup_tail = &(env->movcal_backup);
 137    } 
 138}
 139
 140void helper_ocbi(CPUSH4State *env, uint32_t address)
 141{
 142    memory_content **current = &(env->movcal_backup);
 143    while (*current)
 144    {
 145        uint32_t a = (*current)->address;
 146        if ((a & ~0x1F) == (address & ~0x1F))
 147        {
 148            memory_content *next = (*current)->next;
 149            cpu_stl_data(env, a, (*current)->value);
 150            
 151            if (next == NULL)
 152            {
 153                env->movcal_backup_tail = current;
 154            }
 155
 156            g_free(*current);
 157            *current = next;
 158            break;
 159        }
 160    }
 161}
 162
 163void helper_macl(CPUSH4State *env, uint32_t arg0, uint32_t arg1)
 164{
 165    int64_t res;
 166
 167    res = ((uint64_t) env->mach << 32) | env->macl;
 168    res += (int64_t) (int32_t) arg0 *(int64_t) (int32_t) arg1;
 169    env->mach = (res >> 32) & 0xffffffff;
 170    env->macl = res & 0xffffffff;
 171    if (env->sr & (1u << SR_S)) {
 172        if (res < 0)
 173            env->mach |= 0xffff0000;
 174        else
 175            env->mach &= 0x00007fff;
 176    }
 177}
 178
 179void helper_macw(CPUSH4State *env, uint32_t arg0, uint32_t arg1)
 180{
 181    int64_t res;
 182
 183    res = ((uint64_t) env->mach << 32) | env->macl;
 184    res += (int64_t) (int16_t) arg0 *(int64_t) (int16_t) arg1;
 185    env->mach = (res >> 32) & 0xffffffff;
 186    env->macl = res & 0xffffffff;
 187    if (env->sr & (1u << SR_S)) {
 188        if (res < -0x80000000) {
 189            env->mach = 1;
 190            env->macl = 0x80000000;
 191        } else if (res > 0x000000007fffffff) {
 192            env->mach = 1;
 193            env->macl = 0x7fffffff;
 194        }
 195    }
 196}
 197
 198void helper_ld_fpscr(CPUSH4State *env, uint32_t val)
 199{
 200    env->fpscr = val & FPSCR_MASK;
 201    if ((val & FPSCR_RM_MASK) == FPSCR_RM_ZERO) {
 202        set_float_rounding_mode(float_round_to_zero, &env->fp_status);
 203    } else {
 204        set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
 205    }
 206    set_flush_to_zero((val & FPSCR_DN) != 0, &env->fp_status);
 207}
 208
 209static void update_fpscr(CPUSH4State *env, uintptr_t retaddr)
 210{
 211    int xcpt, cause, enable;
 212
 213    xcpt = get_float_exception_flags(&env->fp_status);
 214
 215    /* Clear the cause entries */
 216    env->fpscr &= ~FPSCR_CAUSE_MASK;
 217
 218    if (unlikely(xcpt)) {
 219        if (xcpt & float_flag_invalid) {
 220            env->fpscr |= FPSCR_CAUSE_V;
 221        }
 222        if (xcpt & float_flag_divbyzero) {
 223            env->fpscr |= FPSCR_CAUSE_Z;
 224        }
 225        if (xcpt & float_flag_overflow) {
 226            env->fpscr |= FPSCR_CAUSE_O;
 227        }
 228        if (xcpt & float_flag_underflow) {
 229            env->fpscr |= FPSCR_CAUSE_U;
 230        }
 231        if (xcpt & float_flag_inexact) {
 232            env->fpscr |= FPSCR_CAUSE_I;
 233        }
 234
 235        /* Accumulate in flag entries */
 236        env->fpscr |= (env->fpscr & FPSCR_CAUSE_MASK)
 237                      >> (FPSCR_CAUSE_SHIFT - FPSCR_FLAG_SHIFT);
 238
 239        /* Generate an exception if enabled */
 240        cause = (env->fpscr & FPSCR_CAUSE_MASK) >> FPSCR_CAUSE_SHIFT;
 241        enable = (env->fpscr & FPSCR_ENABLE_MASK) >> FPSCR_ENABLE_SHIFT;
 242        if (cause & enable) {
 243            raise_exception(env, 0x120, retaddr);
 244        }
 245    }
 246}
 247
 248float32 helper_fadd_FT(CPUSH4State *env, float32 t0, float32 t1)
 249{
 250    set_float_exception_flags(0, &env->fp_status);
 251    t0 = float32_add(t0, t1, &env->fp_status);
 252    update_fpscr(env, GETPC());
 253    return t0;
 254}
 255
 256float64 helper_fadd_DT(CPUSH4State *env, float64 t0, float64 t1)
 257{
 258    set_float_exception_flags(0, &env->fp_status);
 259    t0 = float64_add(t0, t1, &env->fp_status);
 260    update_fpscr(env, GETPC());
 261    return t0;
 262}
 263
 264uint32_t helper_fcmp_eq_FT(CPUSH4State *env, float32 t0, float32 t1)
 265{
 266    int relation;
 267
 268    set_float_exception_flags(0, &env->fp_status);
 269    relation = float32_compare(t0, t1, &env->fp_status);
 270    update_fpscr(env, GETPC());
 271    return relation == float_relation_equal;
 272}
 273
 274uint32_t helper_fcmp_eq_DT(CPUSH4State *env, float64 t0, float64 t1)
 275{
 276    int relation;
 277
 278    set_float_exception_flags(0, &env->fp_status);
 279    relation = float64_compare(t0, t1, &env->fp_status);
 280    update_fpscr(env, GETPC());
 281    return relation == float_relation_equal;
 282}
 283
 284uint32_t helper_fcmp_gt_FT(CPUSH4State *env, float32 t0, float32 t1)
 285{
 286    int relation;
 287
 288    set_float_exception_flags(0, &env->fp_status);
 289    relation = float32_compare(t0, t1, &env->fp_status);
 290    update_fpscr(env, GETPC());
 291    return relation == float_relation_greater;
 292}
 293
 294uint32_t helper_fcmp_gt_DT(CPUSH4State *env, float64 t0, float64 t1)
 295{
 296    int relation;
 297
 298    set_float_exception_flags(0, &env->fp_status);
 299    relation = float64_compare(t0, t1, &env->fp_status);
 300    update_fpscr(env, GETPC());
 301    return relation == float_relation_greater;
 302}
 303
 304float64 helper_fcnvsd_FT_DT(CPUSH4State *env, float32 t0)
 305{
 306    float64 ret;
 307    set_float_exception_flags(0, &env->fp_status);
 308    ret = float32_to_float64(t0, &env->fp_status);
 309    update_fpscr(env, GETPC());
 310    return ret;
 311}
 312
 313float32 helper_fcnvds_DT_FT(CPUSH4State *env, float64 t0)
 314{
 315    float32 ret;
 316    set_float_exception_flags(0, &env->fp_status);
 317    ret = float64_to_float32(t0, &env->fp_status);
 318    update_fpscr(env, GETPC());
 319    return ret;
 320}
 321
 322float32 helper_fdiv_FT(CPUSH4State *env, float32 t0, float32 t1)
 323{
 324    set_float_exception_flags(0, &env->fp_status);
 325    t0 = float32_div(t0, t1, &env->fp_status);
 326    update_fpscr(env, GETPC());
 327    return t0;
 328}
 329
 330float64 helper_fdiv_DT(CPUSH4State *env, float64 t0, float64 t1)
 331{
 332    set_float_exception_flags(0, &env->fp_status);
 333    t0 = float64_div(t0, t1, &env->fp_status);
 334    update_fpscr(env, GETPC());
 335    return t0;
 336}
 337
 338float32 helper_float_FT(CPUSH4State *env, uint32_t t0)
 339{
 340    float32 ret;
 341    set_float_exception_flags(0, &env->fp_status);
 342    ret = int32_to_float32(t0, &env->fp_status);
 343    update_fpscr(env, GETPC());
 344    return ret;
 345}
 346
 347float64 helper_float_DT(CPUSH4State *env, uint32_t t0)
 348{
 349    float64 ret;
 350    set_float_exception_flags(0, &env->fp_status);
 351    ret = int32_to_float64(t0, &env->fp_status);
 352    update_fpscr(env, GETPC());
 353    return ret;
 354}
 355
 356float32 helper_fmac_FT(CPUSH4State *env, float32 t0, float32 t1, float32 t2)
 357{
 358    set_float_exception_flags(0, &env->fp_status);
 359    t0 = float32_muladd(t0, t1, t2, 0, &env->fp_status);
 360    update_fpscr(env, GETPC());
 361    return t0;
 362}
 363
 364float32 helper_fmul_FT(CPUSH4State *env, float32 t0, float32 t1)
 365{
 366    set_float_exception_flags(0, &env->fp_status);
 367    t0 = float32_mul(t0, t1, &env->fp_status);
 368    update_fpscr(env, GETPC());
 369    return t0;
 370}
 371
 372float64 helper_fmul_DT(CPUSH4State *env, float64 t0, float64 t1)
 373{
 374    set_float_exception_flags(0, &env->fp_status);
 375    t0 = float64_mul(t0, t1, &env->fp_status);
 376    update_fpscr(env, GETPC());
 377    return t0;
 378}
 379
 380float32 helper_fsqrt_FT(CPUSH4State *env, float32 t0)
 381{
 382    set_float_exception_flags(0, &env->fp_status);
 383    t0 = float32_sqrt(t0, &env->fp_status);
 384    update_fpscr(env, GETPC());
 385    return t0;
 386}
 387
 388float64 helper_fsqrt_DT(CPUSH4State *env, float64 t0)
 389{
 390    set_float_exception_flags(0, &env->fp_status);
 391    t0 = float64_sqrt(t0, &env->fp_status);
 392    update_fpscr(env, GETPC());
 393    return t0;
 394}
 395
 396float32 helper_fsrra_FT(CPUSH4State *env, float32 t0)
 397{
 398    set_float_exception_flags(0, &env->fp_status);
 399    /* "Approximate" 1/sqrt(x) via actual computation.  */
 400    t0 = float32_sqrt(t0, &env->fp_status);
 401    t0 = float32_div(float32_one, t0, &env->fp_status);
 402    /*
 403     * Since this is supposed to be an approximation, an imprecision
 404     * exception is required.  One supposes this also follows the usual
 405     * IEEE rule that other exceptions take precedence.
 406     */
 407    if (get_float_exception_flags(&env->fp_status) == 0) {
 408        set_float_exception_flags(float_flag_inexact, &env->fp_status);
 409    }
 410    update_fpscr(env, GETPC());
 411    return t0;
 412}
 413
 414float32 helper_fsub_FT(CPUSH4State *env, float32 t0, float32 t1)
 415{
 416    set_float_exception_flags(0, &env->fp_status);
 417    t0 = float32_sub(t0, t1, &env->fp_status);
 418    update_fpscr(env, GETPC());
 419    return t0;
 420}
 421
 422float64 helper_fsub_DT(CPUSH4State *env, float64 t0, float64 t1)
 423{
 424    set_float_exception_flags(0, &env->fp_status);
 425    t0 = float64_sub(t0, t1, &env->fp_status);
 426    update_fpscr(env, GETPC());
 427    return t0;
 428}
 429
 430uint32_t helper_ftrc_FT(CPUSH4State *env, float32 t0)
 431{
 432    uint32_t ret;
 433    set_float_exception_flags(0, &env->fp_status);
 434    ret = float32_to_int32_round_to_zero(t0, &env->fp_status);
 435    update_fpscr(env, GETPC());
 436    return ret;
 437}
 438
 439uint32_t helper_ftrc_DT(CPUSH4State *env, float64 t0)
 440{
 441    uint32_t ret;
 442    set_float_exception_flags(0, &env->fp_status);
 443    ret = float64_to_int32_round_to_zero(t0, &env->fp_status);
 444    update_fpscr(env, GETPC());
 445    return ret;
 446}
 447
 448void helper_fipr(CPUSH4State *env, uint32_t m, uint32_t n)
 449{
 450    int bank, i;
 451    float32 r, p;
 452
 453    bank = (env->sr & FPSCR_FR) ? 16 : 0;
 454    r = float32_zero;
 455    set_float_exception_flags(0, &env->fp_status);
 456
 457    for (i = 0 ; i < 4 ; i++) {
 458        p = float32_mul(env->fregs[bank + m + i],
 459                        env->fregs[bank + n + i],
 460                        &env->fp_status);
 461        r = float32_add(r, p, &env->fp_status);
 462    }
 463    update_fpscr(env, GETPC());
 464
 465    env->fregs[bank + n + 3] = r;
 466}
 467
 468void helper_ftrv(CPUSH4State *env, uint32_t n)
 469{
 470    int bank_matrix, bank_vector;
 471    int i, j;
 472    float32 r[4];
 473    float32 p;
 474
 475    bank_matrix = (env->sr & FPSCR_FR) ? 0 : 16;
 476    bank_vector = (env->sr & FPSCR_FR) ? 16 : 0;
 477    set_float_exception_flags(0, &env->fp_status);
 478    for (i = 0 ; i < 4 ; i++) {
 479        r[i] = float32_zero;
 480        for (j = 0 ; j < 4 ; j++) {
 481            p = float32_mul(env->fregs[bank_matrix + 4 * j + i],
 482                            env->fregs[bank_vector + j],
 483                            &env->fp_status);
 484            r[i] = float32_add(r[i], p, &env->fp_status);
 485        }
 486    }
 487    update_fpscr(env, GETPC());
 488
 489    for (i = 0 ; i < 4 ; i++) {
 490        env->fregs[bank_vector + i] = r[i];
 491    }
 492}
 493