qemu

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

op_helper.c (11896B)


      1 /*
      2  *  RX helper functions
      3  *
      4  *  Copyright (c) 2019 Yoshinori Sato
      5  *
      6  * This program is free software; you can redistribute it and/or modify it
      7  * under the terms and conditions of the GNU General Public License,
      8  * version 2 or later, as published by the Free Software Foundation.
      9  *
     10  * This program is distributed in the hope it will be useful, but WITHOUT
     11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
     13  * more details.
     14  *
     15  * You should have received a copy of the GNU General Public License along with
     16  * this program.  If not, see <http://www.gnu.org/licenses/>.
     17  */
     18 
     19 #include "qemu/osdep.h"
     20 #include "qemu/bitops.h"
     21 #include "cpu.h"
     22 #include "exec/exec-all.h"
     23 #include "exec/helper-proto.h"
     24 #include "exec/cpu_ldst.h"
     25 #include "fpu/softfloat.h"
     26 
     27 static inline G_NORETURN
     28 void raise_exception(CPURXState *env, int index,
     29                      uintptr_t retaddr);
     30 
     31 static void _set_psw(CPURXState *env, uint32_t psw, uint32_t rte)
     32 {
     33     uint32_t prev_u;
     34     prev_u = env->psw_u;
     35     rx_cpu_unpack_psw(env, psw, rte);
     36     if (prev_u != env->psw_u) {
     37         /* switch r0  */
     38         if (env->psw_u) {
     39             env->isp = env->regs[0];
     40             env->regs[0] = env->usp;
     41         } else {
     42             env->usp = env->regs[0];
     43             env->regs[0] = env->isp;
     44         }
     45     }
     46 }
     47 
     48 void helper_set_psw(CPURXState *env, uint32_t psw)
     49 {
     50     _set_psw(env, psw, 0);
     51 }
     52 
     53 void helper_set_psw_rte(CPURXState *env, uint32_t psw)
     54 {
     55     _set_psw(env, psw, 1);
     56 }
     57 
     58 uint32_t helper_pack_psw(CPURXState *env)
     59 {
     60     return rx_cpu_pack_psw(env);
     61 }
     62 
     63 #define SET_FPSW(b)                                             \
     64     do {                                                        \
     65         env->fpsw = FIELD_DP32(env->fpsw, FPSW, C ## b, 1);     \
     66         if (!FIELD_EX32(env->fpsw, FPSW, E ## b)) {             \
     67             env->fpsw = FIELD_DP32(env->fpsw, FPSW, F ## b, 1); \
     68         }                                                       \
     69     } while (0)
     70 
     71 /* fp operations */
     72 static void update_fpsw(CPURXState *env, float32 ret, uintptr_t retaddr)
     73 {
     74     int xcpt, cause, enable;
     75 
     76     env->psw_z = ret & ~(1 << 31); /* mask sign bit */
     77     env->psw_s = ret;
     78 
     79     xcpt = get_float_exception_flags(&env->fp_status);
     80 
     81     /* Clear the cause entries */
     82     env->fpsw = FIELD_DP32(env->fpsw, FPSW, CAUSE, 0);
     83 
     84     /* set FPSW */
     85     if (unlikely(xcpt)) {
     86         if (xcpt & float_flag_invalid) {
     87             SET_FPSW(V);
     88         }
     89         if (xcpt & float_flag_divbyzero) {
     90             SET_FPSW(Z);
     91         }
     92         if (xcpt & float_flag_overflow) {
     93             SET_FPSW(O);
     94         }
     95         if (xcpt & float_flag_underflow) {
     96             SET_FPSW(U);
     97         }
     98         if (xcpt & float_flag_inexact) {
     99             SET_FPSW(X);
    100         }
    101         if ((xcpt & (float_flag_input_denormal
    102                      | float_flag_output_denormal))
    103             && !FIELD_EX32(env->fpsw, FPSW, DN)) {
    104             env->fpsw = FIELD_DP32(env->fpsw, FPSW, CE, 1);
    105         }
    106 
    107         /* update FPSW_FLAG_S */
    108         if (FIELD_EX32(env->fpsw, FPSW, FLAGS) != 0) {
    109             env->fpsw = FIELD_DP32(env->fpsw, FPSW, FS, 1);
    110         }
    111 
    112         /* Generate an exception if enabled */
    113         cause = FIELD_EX32(env->fpsw, FPSW, CAUSE);
    114         enable = FIELD_EX32(env->fpsw, FPSW, ENABLE);
    115         enable |= 1 << 5; /* CE always enabled */
    116         if (cause & enable) {
    117             raise_exception(env, 21, retaddr);
    118         }
    119     }
    120 }
    121 
    122 void helper_set_fpsw(CPURXState *env, uint32_t val)
    123 {
    124     static const int roundmode[] = {
    125         float_round_nearest_even,
    126         float_round_to_zero,
    127         float_round_up,
    128         float_round_down,
    129     };
    130     uint32_t fpsw = env->fpsw;
    131     fpsw |= 0x7fffff03;
    132     val &= ~0x80000000;
    133     fpsw &= val;
    134     FIELD_DP32(fpsw, FPSW, FS, FIELD_EX32(fpsw, FPSW, FLAGS) != 0);
    135     env->fpsw = fpsw;
    136     set_float_rounding_mode(roundmode[FIELD_EX32(env->fpsw, FPSW, RM)],
    137                             &env->fp_status);
    138 }
    139 
    140 #define FLOATOP(op, func)                                           \
    141     float32 helper_##op(CPURXState *env, float32 t0, float32 t1)    \
    142     {                                                               \
    143         float32 ret;                                                \
    144         ret = func(t0, t1, &env->fp_status);                        \
    145         update_fpsw(env, *(uint32_t *)&ret, GETPC());               \
    146         return ret;                                                 \
    147     }
    148 
    149 FLOATOP(fadd, float32_add)
    150 FLOATOP(fsub, float32_sub)
    151 FLOATOP(fmul, float32_mul)
    152 FLOATOP(fdiv, float32_div)
    153 
    154 void helper_fcmp(CPURXState *env, float32 t0, float32 t1)
    155 {
    156     int st;
    157     st = float32_compare(t0, t1, &env->fp_status);
    158     update_fpsw(env, 0, GETPC());
    159     env->psw_z = 1;
    160     env->psw_s = env->psw_o = 0;
    161     switch (st) {
    162     case float_relation_equal:
    163         env->psw_z = 0;
    164         break;
    165     case float_relation_less:
    166         env->psw_s = -1;
    167         break;
    168     case float_relation_unordered:
    169         env->psw_o = -1;
    170         break;
    171     }
    172 }
    173 
    174 uint32_t helper_ftoi(CPURXState *env, float32 t0)
    175 {
    176     uint32_t ret;
    177     ret = float32_to_int32_round_to_zero(t0, &env->fp_status);
    178     update_fpsw(env, ret, GETPC());
    179     return ret;
    180 }
    181 
    182 uint32_t helper_round(CPURXState *env, float32 t0)
    183 {
    184     uint32_t ret;
    185     ret = float32_to_int32(t0, &env->fp_status);
    186     update_fpsw(env, ret, GETPC());
    187     return ret;
    188 }
    189 
    190 float32 helper_itof(CPURXState *env, uint32_t t0)
    191 {
    192     float32 ret;
    193     ret = int32_to_float32(t0, &env->fp_status);
    194     update_fpsw(env, ret, GETPC());
    195     return ret;
    196 }
    197 
    198 /* string operations */
    199 void helper_scmpu(CPURXState *env)
    200 {
    201     uint8_t tmp0, tmp1;
    202     if (env->regs[3] == 0) {
    203         return;
    204     }
    205     do {
    206         tmp0 = cpu_ldub_data_ra(env, env->regs[1]++, GETPC());
    207         tmp1 = cpu_ldub_data_ra(env, env->regs[2]++, GETPC());
    208         env->regs[3]--;
    209         if (tmp0 != tmp1 || tmp0 == '\0') {
    210             break;
    211         }
    212     } while (env->regs[3] != 0);
    213     env->psw_z = tmp0 - tmp1;
    214     env->psw_c = (tmp0 >= tmp1);
    215 }
    216 
    217 static uint32_t (* const cpu_ldufn[])(CPUArchState *env,
    218                                      target_ulong ptr,
    219                                      uintptr_t retaddr) = {
    220     cpu_ldub_data_ra, cpu_lduw_data_ra, cpu_ldl_data_ra,
    221 };
    222 
    223 static uint32_t (* const cpu_ldfn[])(CPUArchState *env,
    224                                      target_ulong ptr,
    225                                      uintptr_t retaddr) = {
    226     cpu_ldub_data_ra, cpu_lduw_data_ra, cpu_ldl_data_ra,
    227 };
    228 
    229 static void (* const cpu_stfn[])(CPUArchState *env,
    230                                  target_ulong ptr,
    231                                  uint32_t val,
    232                                  uintptr_t retaddr) = {
    233     cpu_stb_data_ra, cpu_stw_data_ra, cpu_stl_data_ra,
    234 };
    235 
    236 void helper_sstr(CPURXState *env, uint32_t sz)
    237 {
    238     tcg_debug_assert(sz < 3);
    239     while (env->regs[3] != 0) {
    240         cpu_stfn[sz](env, env->regs[1], env->regs[2], GETPC());
    241         env->regs[1] += 1 << sz;
    242         env->regs[3]--;
    243     }
    244 }
    245 
    246 #define OP_SMOVU 1
    247 #define OP_SMOVF 0
    248 #define OP_SMOVB 2
    249 
    250 static void smov(uint32_t mode, CPURXState *env)
    251 {
    252     uint8_t tmp;
    253     int dir;
    254 
    255     dir = (mode & OP_SMOVB) ? -1 : 1;
    256     while (env->regs[3] != 0) {
    257         tmp = cpu_ldub_data_ra(env, env->regs[2], GETPC());
    258         cpu_stb_data_ra(env, env->regs[1], tmp, GETPC());
    259         env->regs[1] += dir;
    260         env->regs[2] += dir;
    261         env->regs[3]--;
    262         if ((mode & OP_SMOVU) && tmp == 0) {
    263             break;
    264         }
    265     }
    266 }
    267 
    268 void helper_smovu(CPURXState *env)
    269 {
    270     smov(OP_SMOVU, env);
    271 }
    272 
    273 void helper_smovf(CPURXState *env)
    274 {
    275     smov(OP_SMOVF, env);
    276 }
    277 
    278 void helper_smovb(CPURXState *env)
    279 {
    280     smov(OP_SMOVB, env);
    281 }
    282 
    283 
    284 void helper_suntil(CPURXState *env, uint32_t sz)
    285 {
    286     uint32_t tmp;
    287     tcg_debug_assert(sz < 3);
    288     if (env->regs[3] == 0) {
    289         return;
    290     }
    291     do {
    292         tmp = cpu_ldufn[sz](env, env->regs[1], GETPC());
    293         env->regs[1] += 1 << sz;
    294         env->regs[3]--;
    295         if (tmp == env->regs[2]) {
    296             break;
    297         }
    298     } while (env->regs[3] != 0);
    299     env->psw_z = tmp - env->regs[2];
    300     env->psw_c = (tmp <= env->regs[2]);
    301 }
    302 
    303 void helper_swhile(CPURXState *env, uint32_t sz)
    304 {
    305     uint32_t tmp;
    306     tcg_debug_assert(sz < 3);
    307     if (env->regs[3] == 0) {
    308         return;
    309     }
    310     do {
    311         tmp = cpu_ldufn[sz](env, env->regs[1], GETPC());
    312         env->regs[1] += 1 << sz;
    313         env->regs[3]--;
    314         if (tmp != env->regs[2]) {
    315             break;
    316         }
    317     } while (env->regs[3] != 0);
    318     env->psw_z = env->regs[3];
    319     env->psw_c = (tmp <= env->regs[2]);
    320 }
    321 
    322 /* accumulator operations */
    323 void helper_rmpa(CPURXState *env, uint32_t sz)
    324 {
    325     uint64_t result_l, prev;
    326     int32_t result_h;
    327     int64_t tmp0, tmp1;
    328 
    329     if (env->regs[3] == 0) {
    330         return;
    331     }
    332     result_l = env->regs[5];
    333     result_l <<= 32;
    334     result_l |= env->regs[4];
    335     result_h = env->regs[6];
    336     env->psw_o = 0;
    337 
    338     while (env->regs[3] != 0) {
    339         tmp0 = cpu_ldfn[sz](env, env->regs[1], GETPC());
    340         tmp1 = cpu_ldfn[sz](env, env->regs[2], GETPC());
    341         tmp0 *= tmp1;
    342         prev = result_l;
    343         result_l += tmp0;
    344         /* carry / bollow */
    345         if (tmp0 < 0) {
    346             if (prev > result_l) {
    347                 result_h--;
    348             }
    349         } else {
    350             if (prev < result_l) {
    351                 result_h++;
    352             }
    353         }
    354 
    355         env->regs[1] += 1 << sz;
    356         env->regs[2] += 1 << sz;
    357     }
    358     env->psw_s = result_h;
    359     env->psw_o = (result_h != 0 && result_h != -1) << 31;
    360     env->regs[6] = result_h;
    361     env->regs[5] = result_l >> 32;
    362     env->regs[4] = result_l & 0xffffffff;
    363 }
    364 
    365 void helper_racw(CPURXState *env, uint32_t imm)
    366 {
    367     int64_t acc;
    368     acc = env->acc;
    369     acc <<= (imm + 1);
    370     acc += 0x0000000080000000LL;
    371     if (acc > 0x00007fff00000000LL) {
    372         acc = 0x00007fff00000000LL;
    373     } else if (acc < -0x800000000000LL) {
    374         acc = -0x800000000000LL;
    375     } else {
    376         acc &= 0xffffffff00000000LL;
    377     }
    378     env->acc = acc;
    379 }
    380 
    381 void helper_satr(CPURXState *env)
    382 {
    383     if (env->psw_o >> 31) {
    384         if ((int)env->psw_s < 0) {
    385             env->regs[6] = 0x00000000;
    386             env->regs[5] = 0x7fffffff;
    387             env->regs[4] = 0xffffffff;
    388         } else {
    389             env->regs[6] = 0xffffffff;
    390             env->regs[5] = 0x80000000;
    391             env->regs[4] = 0x00000000;
    392         }
    393     }
    394 }
    395 
    396 /* div */
    397 uint32_t helper_div(CPURXState *env, uint32_t num, uint32_t den)
    398 {
    399     uint32_t ret = num;
    400     if (!((num == INT_MIN && den == -1) || den == 0)) {
    401         ret = (int32_t)num / (int32_t)den;
    402         env->psw_o = 0;
    403     } else {
    404         env->psw_o = -1;
    405     }
    406     return ret;
    407 }
    408 
    409 uint32_t helper_divu(CPURXState *env, uint32_t num, uint32_t den)
    410 {
    411     uint32_t ret = num;
    412     if (den != 0) {
    413         ret = num / den;
    414         env->psw_o = 0;
    415     } else {
    416         env->psw_o = -1;
    417     }
    418     return ret;
    419 }
    420 
    421 /* exception */
    422 static inline G_NORETURN
    423 void raise_exception(CPURXState *env, int index,
    424                      uintptr_t retaddr)
    425 {
    426     CPUState *cs = env_cpu(env);
    427 
    428     cs->exception_index = index;
    429     cpu_loop_exit_restore(cs, retaddr);
    430 }
    431 
    432 G_NORETURN void helper_raise_privilege_violation(CPURXState *env)
    433 {
    434     raise_exception(env, 20, GETPC());
    435 }
    436 
    437 G_NORETURN void helper_raise_access_fault(CPURXState *env)
    438 {
    439     raise_exception(env, 21, GETPC());
    440 }
    441 
    442 G_NORETURN void helper_raise_illegal_instruction(CPURXState *env)
    443 {
    444     raise_exception(env, 23, GETPC());
    445 }
    446 
    447 G_NORETURN void helper_wait(CPURXState *env)
    448 {
    449     CPUState *cs = env_cpu(env);
    450 
    451     cs->halted = 1;
    452     env->in_sleep = 1;
    453     env->psw_i = 1;
    454     raise_exception(env, EXCP_HLT, 0);
    455 }
    456 
    457 G_NORETURN void helper_rxint(CPURXState *env, uint32_t vec)
    458 {
    459     raise_exception(env, 0x100 + vec, 0);
    460 }
    461 
    462 G_NORETURN void helper_rxbrk(CPURXState *env)
    463 {
    464     raise_exception(env, 0x100, 0);
    465 }