qemu

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

op_helper.c (12934B)


      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 
     28 void 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 
     51 void 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 
     60 static inline G_NORETURN
     61 void 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 
     70 void helper_raise_illegal_instruction(CPUSH4State *env)
     71 {
     72     raise_exception(env, 0x180, 0);
     73 }
     74 
     75 void helper_raise_slot_illegal_instruction(CPUSH4State *env)
     76 {
     77     raise_exception(env, 0x1a0, 0);
     78 }
     79 
     80 void helper_raise_fpu_disable(CPUSH4State *env)
     81 {
     82     raise_exception(env, 0x800, 0);
     83 }
     84 
     85 void helper_raise_slot_fpu_disable(CPUSH4State *env)
     86 {
     87     raise_exception(env, 0x820, 0);
     88 }
     89 
     90 void 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 
     99 void helper_trapa(CPUSH4State *env, uint32_t tra)
    100 {
    101     env->tra = tra << 2;
    102     raise_exception(env, 0x160, 0);
    103 }
    104 
    105 void 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 
    111 void 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 
    126 void 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 
    140 void 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 
    163 void 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 
    179 void 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 
    198 void 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 
    209 static 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 
    248 float32 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 
    256 float64 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 
    264 uint32_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 
    274 uint32_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 
    284 uint32_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 
    294 uint32_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 
    304 float64 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 
    313 float32 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 
    322 float32 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 
    330 float64 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 
    338 float32 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 
    347 float64 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 
    356 float32 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 
    364 float32 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 
    372 float64 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 
    380 float32 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 
    388 float64 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 
    396 float32 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 
    414 float32 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 
    422 float64 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 
    430 uint32_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 
    439 uint32_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 
    448 void 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 
    468 void 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 }