2 * MIPS emulation load/store helpers for QEMU.
4 * Copyright (c) 2004-2005 Jocelyn Mayer
6 * SPDX-License-Identifier: LGPL-2.1-or-later
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.
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.
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/>.
23 #include "qemu/osdep.h"
25 #include "exec/helper-proto.h"
26 #include "exec/exec-all.h"
27 #include "exec/memop.h"
30 #ifndef CONFIG_USER_ONLY
32 #define HELPER_LD_ATOMIC(name, insn, almask, do_cast) \
33 target_ulong helper_##name(CPUMIPSState *env, target_ulong arg, int mem_idx) \
36 if (!(env->hflags & MIPS_HFLAG_DM)) { \
37 env->CP0_BadVAddr = arg; \
39 do_raise_exception(env, EXCP_AdEL, GETPC()); \
41 env->CP0_LLAddr = cpu_mips_translate_address(env, arg, MMU_DATA_LOAD, \
44 env->llval = do_cast cpu_##insn##_mmuidx_ra(env, arg, mem_idx, GETPC()); \
47 HELPER_LD_ATOMIC(ll
, ldl
, 0x3, (target_long
)(int32_t))
49 HELPER_LD_ATOMIC(lld
, ldq
, 0x7, (target_ulong
))
51 #undef HELPER_LD_ATOMIC
53 #endif /* !CONFIG_USER_ONLY */
55 static inline bool cpu_is_bigendian(CPUMIPSState
*env
)
57 return extract32(env
->CP0_Config0
, CP0C0_BE
, 1);
60 static inline target_ulong
get_lmask(CPUMIPSState
*env
,
61 target_ulong value
, unsigned bits
)
63 unsigned mask
= (bits
/ BITS_PER_BYTE
) - 1;
67 if (!cpu_is_bigendian(env
)) {
74 void helper_swl(CPUMIPSState
*env
, target_ulong arg1
, target_ulong arg2
,
77 target_ulong lmask
= get_lmask(env
, arg2
, 32);
78 int dir
= cpu_is_bigendian(env
) ? 1 : -1;
80 cpu_stb_mmuidx_ra(env
, arg2
, (uint8_t)(arg1
>> 24), mem_idx
, GETPC());
83 cpu_stb_mmuidx_ra(env
, arg2
+ 1 * dir
, (uint8_t)(arg1
>> 16),
88 cpu_stb_mmuidx_ra(env
, arg2
+ 2 * dir
, (uint8_t)(arg1
>> 8),
93 cpu_stb_mmuidx_ra(env
, arg2
+ 3 * dir
, (uint8_t)arg1
,
98 void helper_swr(CPUMIPSState
*env
, target_ulong arg1
, target_ulong arg2
,
101 target_ulong lmask
= get_lmask(env
, arg2
, 32);
102 int dir
= cpu_is_bigendian(env
) ? 1 : -1;
104 cpu_stb_mmuidx_ra(env
, arg2
, (uint8_t)arg1
, mem_idx
, GETPC());
107 cpu_stb_mmuidx_ra(env
, arg2
- 1 * dir
, (uint8_t)(arg1
>> 8),
112 cpu_stb_mmuidx_ra(env
, arg2
- 2 * dir
, (uint8_t)(arg1
>> 16),
117 cpu_stb_mmuidx_ra(env
, arg2
- 3 * dir
, (uint8_t)(arg1
>> 24),
122 #if defined(TARGET_MIPS64)
124 * "half" load and stores. We must do the memory access inline,
125 * or fault handling won't work.
128 void helper_sdl(CPUMIPSState
*env
, target_ulong arg1
, target_ulong arg2
,
131 target_ulong lmask
= get_lmask(env
, arg2
, 64);
132 int dir
= cpu_is_bigendian(env
) ? 1 : -1;
134 cpu_stb_mmuidx_ra(env
, arg2
, (uint8_t)(arg1
>> 56), mem_idx
, GETPC());
137 cpu_stb_mmuidx_ra(env
, arg2
+ 1 * dir
, (uint8_t)(arg1
>> 48),
142 cpu_stb_mmuidx_ra(env
, arg2
+ 2 * dir
, (uint8_t)(arg1
>> 40),
147 cpu_stb_mmuidx_ra(env
, arg2
+ 3 * dir
, (uint8_t)(arg1
>> 32),
152 cpu_stb_mmuidx_ra(env
, arg2
+ 4 * dir
, (uint8_t)(arg1
>> 24),
157 cpu_stb_mmuidx_ra(env
, arg2
+ 5 * dir
, (uint8_t)(arg1
>> 16),
162 cpu_stb_mmuidx_ra(env
, arg2
+ 6 * dir
, (uint8_t)(arg1
>> 8),
167 cpu_stb_mmuidx_ra(env
, arg2
+ 7 * dir
, (uint8_t)arg1
,
172 void helper_sdr(CPUMIPSState
*env
, target_ulong arg1
, target_ulong arg2
,
175 target_ulong lmask
= get_lmask(env
, arg2
, 64);
176 int dir
= cpu_is_bigendian(env
) ? 1 : -1;
178 cpu_stb_mmuidx_ra(env
, arg2
, (uint8_t)arg1
, mem_idx
, GETPC());
181 cpu_stb_mmuidx_ra(env
, arg2
- 1 * dir
, (uint8_t)(arg1
>> 8),
186 cpu_stb_mmuidx_ra(env
, arg2
- 2 * dir
, (uint8_t)(arg1
>> 16),
191 cpu_stb_mmuidx_ra(env
, arg2
- 3 * dir
, (uint8_t)(arg1
>> 24),
196 cpu_stb_mmuidx_ra(env
, arg2
- 4 * dir
, (uint8_t)(arg1
>> 32),
201 cpu_stb_mmuidx_ra(env
, arg2
- 5 * dir
, (uint8_t)(arg1
>> 40),
206 cpu_stb_mmuidx_ra(env
, arg2
- 6 * dir
, (uint8_t)(arg1
>> 48),
211 cpu_stb_mmuidx_ra(env
, arg2
- 7 * dir
, (uint8_t)(arg1
>> 56),
215 #endif /* TARGET_MIPS64 */
217 static const int multiple_regs
[] = { 16, 17, 18, 19, 20, 21, 22, 23, 30 };
219 void helper_lwm(CPUMIPSState
*env
, target_ulong addr
, target_ulong reglist
,
222 target_ulong base_reglist
= reglist
& 0xf;
223 target_ulong do_r31
= reglist
& 0x10;
225 if (base_reglist
> 0 && base_reglist
<= ARRAY_SIZE(multiple_regs
)) {
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());
236 env
->active_tc
.gpr
[31] =
237 (target_long
)cpu_ldl_mmuidx_ra(env
, addr
, mem_idx
, GETPC());
241 void helper_swm(CPUMIPSState
*env
, target_ulong addr
, target_ulong reglist
,
244 target_ulong base_reglist
= reglist
& 0xf;
245 target_ulong do_r31
= reglist
& 0x10;
247 if (base_reglist
> 0 && base_reglist
<= ARRAY_SIZE(multiple_regs
)) {
250 for (i
= 0; i
< base_reglist
; i
++) {
251 cpu_stl_mmuidx_ra(env
, addr
, env
->active_tc
.gpr
[multiple_regs
[i
]],
258 cpu_stl_mmuidx_ra(env
, addr
, env
->active_tc
.gpr
[31], mem_idx
, GETPC());
262 #if defined(TARGET_MIPS64)
263 void helper_ldm(CPUMIPSState
*env
, target_ulong addr
, target_ulong reglist
,
266 target_ulong base_reglist
= reglist
& 0xf;
267 target_ulong do_r31
= reglist
& 0x10;
269 if (base_reglist
> 0 && base_reglist
<= ARRAY_SIZE(multiple_regs
)) {
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());
280 env
->active_tc
.gpr
[31] =
281 cpu_ldq_mmuidx_ra(env
, addr
, mem_idx
, GETPC());
285 void helper_sdm(CPUMIPSState
*env
, target_ulong addr
, target_ulong reglist
,
288 target_ulong base_reglist
= reglist
& 0xf;
289 target_ulong do_r31
= reglist
& 0x10;
291 if (base_reglist
> 0 && base_reglist
<= ARRAY_SIZE(multiple_regs
)) {
294 for (i
= 0; i
< base_reglist
; i
++) {
295 cpu_stq_mmuidx_ra(env
, addr
, env
->active_tc
.gpr
[multiple_regs
[i
]],
302 cpu_stq_mmuidx_ra(env
, addr
, env
->active_tc
.gpr
[31], mem_idx
, GETPC());
306 #endif /* TARGET_MIPS64 */