qemu

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

ldst_helper.c (9463B)


      1 /*
      2  *  MIPS emulation load/store helpers for QEMU.
      3  *
      4  *  Copyright (c) 2004-2005 Jocelyn Mayer
      5  *
      6  * SPDX-License-Identifier: LGPL-2.1-or-later
      7  *
      8  * This library is free software; you can redistribute it and/or
      9  * modify it under the terms of the GNU Lesser General Public
     10  * License as published by the Free Software Foundation; either
     11  * version 2.1 of the License, or (at your option) any later version.
     12  *
     13  * This library is distributed in the hope that it will be useful,
     14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     16  * Lesser General Public License for more details.
     17  *
     18  * You should have received a copy of the GNU Lesser General Public
     19  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
     20  *
     21  */
     22 
     23 #include "qemu/osdep.h"
     24 #include "cpu.h"
     25 #include "exec/helper-proto.h"
     26 #include "exec/exec-all.h"
     27 #include "exec/memop.h"
     28 #include "internal.h"
     29 
     30 #ifndef CONFIG_USER_ONLY
     31 
     32 #define HELPER_LD_ATOMIC(name, insn, almask, do_cast)                         \
     33 target_ulong helper_##name(CPUMIPSState *env, target_ulong arg, int mem_idx)  \
     34 {                                                                             \
     35     if (arg & almask) {                                                       \
     36         if (!(env->hflags & MIPS_HFLAG_DM)) {                                 \
     37             env->CP0_BadVAddr = arg;                                          \
     38         }                                                                     \
     39         do_raise_exception(env, EXCP_AdEL, GETPC());                          \
     40     }                                                                         \
     41     env->CP0_LLAddr = cpu_mips_translate_address(env, arg, MMU_DATA_LOAD,     \
     42                                                  GETPC());                    \
     43     env->lladdr = arg;                                                        \
     44     env->llval = do_cast cpu_##insn##_mmuidx_ra(env, arg, mem_idx, GETPC());  \
     45     return env->llval;                                                        \
     46 }
     47 HELPER_LD_ATOMIC(ll, ldl, 0x3, (target_long)(int32_t))
     48 #ifdef TARGET_MIPS64
     49 HELPER_LD_ATOMIC(lld, ldq, 0x7, (target_ulong))
     50 #endif
     51 #undef HELPER_LD_ATOMIC
     52 
     53 #endif /* !CONFIG_USER_ONLY */
     54 
     55 static inline bool cpu_is_bigendian(CPUMIPSState *env)
     56 {
     57     return extract32(env->CP0_Config0, CP0C0_BE, 1);
     58 }
     59 
     60 static inline target_ulong get_lmask(CPUMIPSState *env,
     61                                      target_ulong value, unsigned bits)
     62 {
     63     unsigned mask = (bits / BITS_PER_BYTE) - 1;
     64 
     65     value &= mask;
     66 
     67     if (!cpu_is_bigendian(env)) {
     68         value ^= mask;
     69     }
     70 
     71     return value;
     72 }
     73 
     74 void helper_swl(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
     75                 int mem_idx)
     76 {
     77     target_ulong lmask = get_lmask(env, arg2, 32);
     78     int dir = cpu_is_bigendian(env) ? 1 : -1;
     79 
     80     cpu_stb_mmuidx_ra(env, arg2, (uint8_t)(arg1 >> 24), mem_idx, GETPC());
     81 
     82     if (lmask <= 2) {
     83         cpu_stb_mmuidx_ra(env, arg2 + 1 * dir, (uint8_t)(arg1 >> 16),
     84                           mem_idx, GETPC());
     85     }
     86 
     87     if (lmask <= 1) {
     88         cpu_stb_mmuidx_ra(env, arg2 + 2 * dir, (uint8_t)(arg1 >> 8),
     89                           mem_idx, GETPC());
     90     }
     91 
     92     if (lmask == 0) {
     93         cpu_stb_mmuidx_ra(env, arg2 + 3 * dir, (uint8_t)arg1,
     94                           mem_idx, GETPC());
     95     }
     96 }
     97 
     98 void helper_swr(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
     99                 int mem_idx)
    100 {
    101     target_ulong lmask = get_lmask(env, arg2, 32);
    102     int dir = cpu_is_bigendian(env) ? 1 : -1;
    103 
    104     cpu_stb_mmuidx_ra(env, arg2, (uint8_t)arg1, mem_idx, GETPC());
    105 
    106     if (lmask >= 1) {
    107         cpu_stb_mmuidx_ra(env, arg2 - 1 * dir, (uint8_t)(arg1 >> 8),
    108                           mem_idx, GETPC());
    109     }
    110 
    111     if (lmask >= 2) {
    112         cpu_stb_mmuidx_ra(env, arg2 - 2 * dir, (uint8_t)(arg1 >> 16),
    113                           mem_idx, GETPC());
    114     }
    115 
    116     if (lmask == 3) {
    117         cpu_stb_mmuidx_ra(env, arg2 - 3 * dir, (uint8_t)(arg1 >> 24),
    118                           mem_idx, GETPC());
    119     }
    120 }
    121 
    122 #if defined(TARGET_MIPS64)
    123 /*
    124  * "half" load and stores.  We must do the memory access inline,
    125  * or fault handling won't work.
    126  */
    127 
    128 void helper_sdl(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
    129                 int mem_idx)
    130 {
    131     target_ulong lmask = get_lmask(env, arg2, 64);
    132     int dir = cpu_is_bigendian(env) ? 1 : -1;
    133 
    134     cpu_stb_mmuidx_ra(env, arg2, (uint8_t)(arg1 >> 56), mem_idx, GETPC());
    135 
    136     if (lmask <= 6) {
    137         cpu_stb_mmuidx_ra(env, arg2 + 1 * dir, (uint8_t)(arg1 >> 48),
    138                           mem_idx, GETPC());
    139     }
    140 
    141     if (lmask <= 5) {
    142         cpu_stb_mmuidx_ra(env, arg2 + 2 * dir, (uint8_t)(arg1 >> 40),
    143                           mem_idx, GETPC());
    144     }
    145 
    146     if (lmask <= 4) {
    147         cpu_stb_mmuidx_ra(env, arg2 + 3 * dir, (uint8_t)(arg1 >> 32),
    148                           mem_idx, GETPC());
    149     }
    150 
    151     if (lmask <= 3) {
    152         cpu_stb_mmuidx_ra(env, arg2 + 4 * dir, (uint8_t)(arg1 >> 24),
    153                           mem_idx, GETPC());
    154     }
    155 
    156     if (lmask <= 2) {
    157         cpu_stb_mmuidx_ra(env, arg2 + 5 * dir, (uint8_t)(arg1 >> 16),
    158                           mem_idx, GETPC());
    159     }
    160 
    161     if (lmask <= 1) {
    162         cpu_stb_mmuidx_ra(env, arg2 + 6 * dir, (uint8_t)(arg1 >> 8),
    163                           mem_idx, GETPC());
    164     }
    165 
    166     if (lmask <= 0) {
    167         cpu_stb_mmuidx_ra(env, arg2 + 7 * dir, (uint8_t)arg1,
    168                           mem_idx, GETPC());
    169     }
    170 }
    171 
    172 void helper_sdr(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
    173                 int mem_idx)
    174 {
    175     target_ulong lmask = get_lmask(env, arg2, 64);
    176     int dir = cpu_is_bigendian(env) ? 1 : -1;
    177 
    178     cpu_stb_mmuidx_ra(env, arg2, (uint8_t)arg1, mem_idx, GETPC());
    179 
    180     if (lmask >= 1) {
    181         cpu_stb_mmuidx_ra(env, arg2 - 1 * dir, (uint8_t)(arg1 >> 8),
    182                           mem_idx, GETPC());
    183     }
    184 
    185     if (lmask >= 2) {
    186         cpu_stb_mmuidx_ra(env, arg2 - 2 * dir, (uint8_t)(arg1 >> 16),
    187                           mem_idx, GETPC());
    188     }
    189 
    190     if (lmask >= 3) {
    191         cpu_stb_mmuidx_ra(env, arg2 - 3 * dir, (uint8_t)(arg1 >> 24),
    192                           mem_idx, GETPC());
    193     }
    194 
    195     if (lmask >= 4) {
    196         cpu_stb_mmuidx_ra(env, arg2 - 4 * dir, (uint8_t)(arg1 >> 32),
    197                           mem_idx, GETPC());
    198     }
    199 
    200     if (lmask >= 5) {
    201         cpu_stb_mmuidx_ra(env, arg2 - 5 * dir, (uint8_t)(arg1 >> 40),
    202                           mem_idx, GETPC());
    203     }
    204 
    205     if (lmask >= 6) {
    206         cpu_stb_mmuidx_ra(env, arg2 - 6 * dir, (uint8_t)(arg1 >> 48),
    207                           mem_idx, GETPC());
    208     }
    209 
    210     if (lmask == 7) {
    211         cpu_stb_mmuidx_ra(env, arg2 - 7 * dir, (uint8_t)(arg1 >> 56),
    212                           mem_idx, GETPC());
    213     }
    214 }
    215 #endif /* TARGET_MIPS64 */
    216 
    217 static const int multiple_regs[] = { 16, 17, 18, 19, 20, 21, 22, 23, 30 };
    218 
    219 void helper_lwm(CPUMIPSState *env, target_ulong addr, target_ulong reglist,
    220                 uint32_t mem_idx)
    221 {
    222     target_ulong base_reglist = reglist & 0xf;
    223     target_ulong do_r31 = reglist & 0x10;
    224 
    225     if (base_reglist > 0 && base_reglist <= ARRAY_SIZE(multiple_regs)) {
    226         target_ulong i;
    227 
    228         for (i = 0; i < base_reglist; i++) {
    229             env->active_tc.gpr[multiple_regs[i]] =
    230                 (target_long)cpu_ldl_mmuidx_ra(env, addr, mem_idx, GETPC());
    231             addr += 4;
    232         }
    233     }
    234 
    235     if (do_r31) {
    236         env->active_tc.gpr[31] =
    237             (target_long)cpu_ldl_mmuidx_ra(env, addr, mem_idx, GETPC());
    238     }
    239 }
    240 
    241 void helper_swm(CPUMIPSState *env, target_ulong addr, target_ulong reglist,
    242                 uint32_t mem_idx)
    243 {
    244     target_ulong base_reglist = reglist & 0xf;
    245     target_ulong do_r31 = reglist & 0x10;
    246 
    247     if (base_reglist > 0 && base_reglist <= ARRAY_SIZE(multiple_regs)) {
    248         target_ulong i;
    249 
    250         for (i = 0; i < base_reglist; i++) {
    251             cpu_stw_mmuidx_ra(env, addr, env->active_tc.gpr[multiple_regs[i]],
    252                               mem_idx, GETPC());
    253             addr += 4;
    254         }
    255     }
    256 
    257     if (do_r31) {
    258         cpu_stw_mmuidx_ra(env, addr, env->active_tc.gpr[31], mem_idx, GETPC());
    259     }
    260 }
    261 
    262 #if defined(TARGET_MIPS64)
    263 void helper_ldm(CPUMIPSState *env, target_ulong addr, target_ulong reglist,
    264                 uint32_t mem_idx)
    265 {
    266     target_ulong base_reglist = reglist & 0xf;
    267     target_ulong do_r31 = reglist & 0x10;
    268 
    269     if (base_reglist > 0 && base_reglist <= ARRAY_SIZE(multiple_regs)) {
    270         target_ulong i;
    271 
    272         for (i = 0; i < base_reglist; i++) {
    273             env->active_tc.gpr[multiple_regs[i]] =
    274                 cpu_ldq_mmuidx_ra(env, addr, mem_idx, GETPC());
    275             addr += 8;
    276         }
    277     }
    278 
    279     if (do_r31) {
    280         env->active_tc.gpr[31] =
    281             cpu_ldq_mmuidx_ra(env, addr, mem_idx, GETPC());
    282     }
    283 }
    284 
    285 void helper_sdm(CPUMIPSState *env, target_ulong addr, target_ulong reglist,
    286                 uint32_t mem_idx)
    287 {
    288     target_ulong base_reglist = reglist & 0xf;
    289     target_ulong do_r31 = reglist & 0x10;
    290 
    291     if (base_reglist > 0 && base_reglist <= ARRAY_SIZE(multiple_regs)) {
    292         target_ulong i;
    293 
    294         for (i = 0; i < base_reglist; i++) {
    295             cpu_stq_mmuidx_ra(env, addr, env->active_tc.gpr[multiple_regs[i]],
    296                               mem_idx, GETPC());
    297             addr += 8;
    298         }
    299     }
    300 
    301     if (do_r31) {
    302         cpu_stq_mmuidx_ra(env, addr, env->active_tc.gpr[31], mem_idx, GETPC());
    303     }
    304 }
    305 
    306 #endif /* TARGET_MIPS64 */