1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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) \
33target_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}
47HELPER_LD_ATOMIC(ll, ldl, 0x3, (target_long)(int32_t))
48#ifdef TARGET_MIPS64
49HELPER_LD_ATOMIC(lld, ldq, 0x7, (target_ulong))
50#endif
51#undef HELPER_LD_ATOMIC
52
53#endif
54
55static inline bool cpu_is_bigendian(CPUMIPSState *env)
56{
57 return extract32(env->CP0_Config0, CP0C0_BE, 1);
58}
59
60static 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
74void 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
98void 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
125
126
127
128void 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
172void 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
216
217static const int multiple_regs[] = { 16, 17, 18, 19, 20, 21, 22, 23, 30 };
218
219void 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
241void 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)
263void 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
285void 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
307