]>
Commit | Line | Data |
---|---|---|
6af0bf9c FB |
1 | /* |
2 | * MIPS emulation helpers for qemu. | |
5fafdf24 | 3 | * |
6af0bf9c FB |
4 | * Copyright (c) 2004-2005 Jocelyn Mayer |
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 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, write to the Free Software | |
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
19 | */ | |
2d0e944d | 20 | #include <stdlib.h> |
6af0bf9c FB |
21 | #include "exec.h" |
22 | ||
05f778c8 TS |
23 | #include "host-utils.h" |
24 | ||
6af0bf9c FB |
25 | /*****************************************************************************/ |
26 | /* Exceptions processing helpers */ | |
6af0bf9c | 27 | |
6af0bf9c FB |
28 | void do_raise_exception_err (uint32_t exception, int error_code) |
29 | { | |
30 | #if 1 | |
31 | if (logfile && exception < 0x100) | |
32 | fprintf(logfile, "%s: %d %d\n", __func__, exception, error_code); | |
33 | #endif | |
34 | env->exception_index = exception; | |
35 | env->error_code = error_code; | |
6af0bf9c FB |
36 | cpu_loop_exit(); |
37 | } | |
38 | ||
6af0bf9c FB |
39 | void do_raise_exception (uint32_t exception) |
40 | { | |
41 | do_raise_exception_err(exception, 0); | |
42 | } | |
43 | ||
48d38ca5 TS |
44 | void do_interrupt_restart (void) |
45 | { | |
46 | if (!(env->CP0_Status & (1 << CP0St_EXL)) && | |
47 | !(env->CP0_Status & (1 << CP0St_ERL)) && | |
48 | !(env->hflags & MIPS_HFLAG_DM) && | |
49 | (env->CP0_Status & (1 << CP0St_IE)) && | |
50 | (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask)) { | |
51 | env->CP0_Cause &= ~(0x1f << CP0Ca_EC); | |
52 | do_raise_exception(EXCP_EXT_INTERRUPT); | |
53 | } | |
54 | } | |
55 | ||
4ad40f36 FB |
56 | void do_restore_state (void *pc_ptr) |
57 | { | |
a607922c FB |
58 | TranslationBlock *tb; |
59 | unsigned long pc = (unsigned long) pc_ptr; | |
60 | ||
61 | tb = tb_find_pc (pc); | |
62 | if (tb) { | |
63 | cpu_restore_state (tb, env, pc, NULL); | |
64 | } | |
4ad40f36 FB |
65 | } |
66 | ||
be24bb4f | 67 | target_ulong do_clo (target_ulong t0) |
30898801 | 68 | { |
be24bb4f | 69 | return clo32(t0); |
30898801 TS |
70 | } |
71 | ||
be24bb4f | 72 | target_ulong do_clz (target_ulong t0) |
30898801 | 73 | { |
be24bb4f | 74 | return clz32(t0); |
30898801 TS |
75 | } |
76 | ||
d26bc211 | 77 | #if defined(TARGET_MIPS64) |
be24bb4f | 78 | target_ulong do_dclo (target_ulong t0) |
05f778c8 | 79 | { |
be24bb4f | 80 | return clo64(t0); |
05f778c8 TS |
81 | } |
82 | ||
be24bb4f | 83 | target_ulong do_dclz (target_ulong t0) |
05f778c8 | 84 | { |
be24bb4f | 85 | return clz64(t0); |
05f778c8 | 86 | } |
d26bc211 | 87 | #endif /* TARGET_MIPS64 */ |
c570fd16 | 88 | |
6af0bf9c | 89 | /* 64 bits arithmetic for 32 bits hosts */ |
c904ef0e | 90 | static inline uint64_t get_HILO (void) |
6af0bf9c | 91 | { |
b5dc7732 | 92 | return ((uint64_t)(env->active_tc.HI[0]) << 32) | (uint32_t)env->active_tc.LO[0]; |
6af0bf9c FB |
93 | } |
94 | ||
c904ef0e | 95 | static inline void set_HILO (uint64_t HILO) |
6af0bf9c | 96 | { |
b5dc7732 TS |
97 | env->active_tc.LO[0] = (int32_t)HILO; |
98 | env->active_tc.HI[0] = (int32_t)(HILO >> 32); | |
6af0bf9c FB |
99 | } |
100 | ||
c904ef0e | 101 | static inline void set_HIT0_LO (target_ulong t0, uint64_t HILO) |
e9c71dd1 | 102 | { |
b5dc7732 TS |
103 | env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF); |
104 | t0 = env->active_tc.HI[0] = (int32_t)(HILO >> 32); | |
e9c71dd1 TS |
105 | } |
106 | ||
c904ef0e | 107 | static inline void set_HI_LOT0 (target_ulong t0, uint64_t HILO) |
e9c71dd1 | 108 | { |
b5dc7732 TS |
109 | t0 = env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF); |
110 | env->active_tc.HI[0] = (int32_t)(HILO >> 32); | |
e9c71dd1 TS |
111 | } |
112 | ||
92af06d2 | 113 | #if TARGET_LONG_BITS > HOST_LONG_BITS |
be24bb4f | 114 | void do_madd (target_ulong t0, target_ulong t1) |
6af0bf9c FB |
115 | { |
116 | int64_t tmp; | |
117 | ||
be24bb4f | 118 | tmp = ((int64_t)(int32_t)t0 * (int64_t)(int32_t)t1); |
6af0bf9c FB |
119 | set_HILO((int64_t)get_HILO() + tmp); |
120 | } | |
121 | ||
be24bb4f | 122 | void do_maddu (target_ulong t0, target_ulong t1) |
6af0bf9c FB |
123 | { |
124 | uint64_t tmp; | |
125 | ||
be24bb4f | 126 | tmp = ((uint64_t)(uint32_t)t0 * (uint64_t)(uint32_t)t1); |
6af0bf9c FB |
127 | set_HILO(get_HILO() + tmp); |
128 | } | |
129 | ||
be24bb4f | 130 | void do_msub (target_ulong t0, target_ulong t1) |
6af0bf9c FB |
131 | { |
132 | int64_t tmp; | |
133 | ||
be24bb4f | 134 | tmp = ((int64_t)(int32_t)t0 * (int64_t)(int32_t)t1); |
6af0bf9c FB |
135 | set_HILO((int64_t)get_HILO() - tmp); |
136 | } | |
137 | ||
be24bb4f | 138 | void do_msubu (target_ulong t0, target_ulong t1) |
6af0bf9c FB |
139 | { |
140 | uint64_t tmp; | |
141 | ||
be24bb4f | 142 | tmp = ((uint64_t)(uint32_t)t0 * (uint64_t)(uint32_t)t1); |
6af0bf9c FB |
143 | set_HILO(get_HILO() - tmp); |
144 | } | |
92af06d2 | 145 | #endif /* TARGET_LONG_BITS > HOST_LONG_BITS */ |
e9c71dd1 TS |
146 | |
147 | /* Multiplication variants of the vr54xx. */ | |
be24bb4f | 148 | target_ulong do_muls (target_ulong t0, target_ulong t1) |
e9c71dd1 | 149 | { |
be24bb4f TS |
150 | set_HI_LOT0(t0, 0 - ((int64_t)(int32_t)t0 * (int64_t)(int32_t)t1)); |
151 | ||
152 | return t0; | |
e9c71dd1 TS |
153 | } |
154 | ||
be24bb4f | 155 | target_ulong do_mulsu (target_ulong t0, target_ulong t1) |
e9c71dd1 | 156 | { |
be24bb4f TS |
157 | set_HI_LOT0(t0, 0 - ((uint64_t)(uint32_t)t0 * (uint64_t)(uint32_t)t1)); |
158 | ||
159 | return t0; | |
e9c71dd1 TS |
160 | } |
161 | ||
be24bb4f | 162 | target_ulong do_macc (target_ulong t0, target_ulong t1) |
e9c71dd1 | 163 | { |
be24bb4f TS |
164 | set_HI_LOT0(t0, ((int64_t)get_HILO()) + ((int64_t)(int32_t)t0 * (int64_t)(int32_t)t1)); |
165 | ||
166 | return t0; | |
e9c71dd1 TS |
167 | } |
168 | ||
be24bb4f | 169 | target_ulong do_macchi (target_ulong t0, target_ulong t1) |
e9c71dd1 | 170 | { |
be24bb4f TS |
171 | set_HIT0_LO(t0, ((int64_t)get_HILO()) + ((int64_t)(int32_t)t0 * (int64_t)(int32_t)t1)); |
172 | ||
173 | return t0; | |
e9c71dd1 TS |
174 | } |
175 | ||
be24bb4f | 176 | target_ulong do_maccu (target_ulong t0, target_ulong t1) |
e9c71dd1 | 177 | { |
be24bb4f TS |
178 | set_HI_LOT0(t0, ((uint64_t)get_HILO()) + ((uint64_t)(uint32_t)t0 * (uint64_t)(uint32_t)t1)); |
179 | ||
180 | return t0; | |
e9c71dd1 TS |
181 | } |
182 | ||
be24bb4f | 183 | target_ulong do_macchiu (target_ulong t0, target_ulong t1) |
e9c71dd1 | 184 | { |
be24bb4f TS |
185 | set_HIT0_LO(t0, ((uint64_t)get_HILO()) + ((uint64_t)(uint32_t)t0 * (uint64_t)(uint32_t)t1)); |
186 | ||
187 | return t0; | |
e9c71dd1 TS |
188 | } |
189 | ||
be24bb4f | 190 | target_ulong do_msac (target_ulong t0, target_ulong t1) |
e9c71dd1 | 191 | { |
be24bb4f TS |
192 | set_HI_LOT0(t0, ((int64_t)get_HILO()) - ((int64_t)(int32_t)t0 * (int64_t)(int32_t)t1)); |
193 | ||
194 | return t0; | |
e9c71dd1 TS |
195 | } |
196 | ||
be24bb4f | 197 | target_ulong do_msachi (target_ulong t0, target_ulong t1) |
e9c71dd1 | 198 | { |
be24bb4f TS |
199 | set_HIT0_LO(t0, ((int64_t)get_HILO()) - ((int64_t)(int32_t)t0 * (int64_t)(int32_t)t1)); |
200 | ||
201 | return t0; | |
e9c71dd1 TS |
202 | } |
203 | ||
be24bb4f | 204 | target_ulong do_msacu (target_ulong t0, target_ulong t1) |
e9c71dd1 | 205 | { |
be24bb4f TS |
206 | set_HI_LOT0(t0, ((uint64_t)get_HILO()) - ((uint64_t)(uint32_t)t0 * (uint64_t)(uint32_t)t1)); |
207 | ||
208 | return t0; | |
e9c71dd1 TS |
209 | } |
210 | ||
be24bb4f | 211 | target_ulong do_msachiu (target_ulong t0, target_ulong t1) |
e9c71dd1 | 212 | { |
be24bb4f TS |
213 | set_HIT0_LO(t0, ((uint64_t)get_HILO()) - ((uint64_t)(uint32_t)t0 * (uint64_t)(uint32_t)t1)); |
214 | ||
215 | return t0; | |
e9c71dd1 TS |
216 | } |
217 | ||
be24bb4f | 218 | target_ulong do_mulhi (target_ulong t0, target_ulong t1) |
e9c71dd1 | 219 | { |
be24bb4f TS |
220 | set_HIT0_LO(t0, (int64_t)(int32_t)t0 * (int64_t)(int32_t)t1); |
221 | ||
222 | return t0; | |
e9c71dd1 TS |
223 | } |
224 | ||
be24bb4f | 225 | target_ulong do_mulhiu (target_ulong t0, target_ulong t1) |
e9c71dd1 | 226 | { |
be24bb4f TS |
227 | set_HIT0_LO(t0, (uint64_t)(uint32_t)t0 * (uint64_t)(uint32_t)t1); |
228 | ||
229 | return t0; | |
e9c71dd1 TS |
230 | } |
231 | ||
be24bb4f | 232 | target_ulong do_mulshi (target_ulong t0, target_ulong t1) |
e9c71dd1 | 233 | { |
be24bb4f TS |
234 | set_HIT0_LO(t0, 0 - ((int64_t)(int32_t)t0 * (int64_t)(int32_t)t1)); |
235 | ||
236 | return t0; | |
e9c71dd1 TS |
237 | } |
238 | ||
be24bb4f | 239 | target_ulong do_mulshiu (target_ulong t0, target_ulong t1) |
e9c71dd1 | 240 | { |
be24bb4f TS |
241 | set_HIT0_LO(t0, 0 - ((uint64_t)(uint32_t)t0 * (uint64_t)(uint32_t)t1)); |
242 | ||
243 | return t0; | |
e9c71dd1 | 244 | } |
6af0bf9c | 245 | |
214c465f | 246 | #ifdef TARGET_MIPS64 |
be24bb4f | 247 | void do_dmult (target_ulong t0, target_ulong t1) |
214c465f | 248 | { |
b5dc7732 | 249 | muls64(&(env->active_tc.LO[0]), &(env->active_tc.HI[0]), t0, t1); |
214c465f TS |
250 | } |
251 | ||
be24bb4f | 252 | void do_dmultu (target_ulong t0, target_ulong t1) |
214c465f | 253 | { |
b5dc7732 | 254 | mulu64(&(env->active_tc.LO[0]), &(env->active_tc.HI[0]), t0, t1); |
214c465f TS |
255 | } |
256 | #endif | |
257 | ||
c8c2227e TS |
258 | #ifdef TARGET_WORDS_BIGENDIAN |
259 | #define GET_LMASK(v) ((v) & 3) | |
260 | #define GET_OFFSET(addr, offset) (addr + (offset)) | |
261 | #else | |
262 | #define GET_LMASK(v) (((v) & 3) ^ 3) | |
263 | #define GET_OFFSET(addr, offset) (addr - (offset)) | |
264 | #endif | |
265 | ||
be24bb4f | 266 | target_ulong do_lwl(target_ulong t0, target_ulong t1, int mem_idx) |
c8c2227e TS |
267 | { |
268 | target_ulong tmp; | |
269 | ||
270 | #ifdef CONFIG_USER_ONLY | |
271 | #define ldfun ldub_raw | |
272 | #else | |
273 | int (*ldfun)(target_ulong); | |
274 | ||
275 | switch (mem_idx) | |
276 | { | |
277 | case 0: ldfun = ldub_kernel; break; | |
278 | case 1: ldfun = ldub_super; break; | |
279 | default: | |
280 | case 2: ldfun = ldub_user; break; | |
281 | } | |
282 | #endif | |
be24bb4f TS |
283 | tmp = ldfun(t0); |
284 | t1 = (t1 & 0x00FFFFFF) | (tmp << 24); | |
c8c2227e | 285 | |
be24bb4f TS |
286 | if (GET_LMASK(t0) <= 2) { |
287 | tmp = ldfun(GET_OFFSET(t0, 1)); | |
288 | t1 = (t1 & 0xFF00FFFF) | (tmp << 16); | |
c8c2227e TS |
289 | } |
290 | ||
be24bb4f TS |
291 | if (GET_LMASK(t0) <= 1) { |
292 | tmp = ldfun(GET_OFFSET(t0, 2)); | |
293 | t1 = (t1 & 0xFFFF00FF) | (tmp << 8); | |
c8c2227e TS |
294 | } |
295 | ||
be24bb4f TS |
296 | if (GET_LMASK(t0) == 0) { |
297 | tmp = ldfun(GET_OFFSET(t0, 3)); | |
298 | t1 = (t1 & 0xFFFFFF00) | tmp; | |
c8c2227e | 299 | } |
be24bb4f | 300 | return (int32_t)t1; |
c8c2227e TS |
301 | } |
302 | ||
be24bb4f | 303 | target_ulong do_lwr(target_ulong t0, target_ulong t1, int mem_idx) |
c8c2227e TS |
304 | { |
305 | target_ulong tmp; | |
306 | ||
307 | #ifdef CONFIG_USER_ONLY | |
308 | #define ldfun ldub_raw | |
309 | #else | |
310 | int (*ldfun)(target_ulong); | |
311 | ||
312 | switch (mem_idx) | |
313 | { | |
314 | case 0: ldfun = ldub_kernel; break; | |
315 | case 1: ldfun = ldub_super; break; | |
316 | default: | |
317 | case 2: ldfun = ldub_user; break; | |
318 | } | |
319 | #endif | |
be24bb4f TS |
320 | tmp = ldfun(t0); |
321 | t1 = (t1 & 0xFFFFFF00) | tmp; | |
c8c2227e | 322 | |
be24bb4f TS |
323 | if (GET_LMASK(t0) >= 1) { |
324 | tmp = ldfun(GET_OFFSET(t0, -1)); | |
325 | t1 = (t1 & 0xFFFF00FF) | (tmp << 8); | |
c8c2227e TS |
326 | } |
327 | ||
be24bb4f TS |
328 | if (GET_LMASK(t0) >= 2) { |
329 | tmp = ldfun(GET_OFFSET(t0, -2)); | |
330 | t1 = (t1 & 0xFF00FFFF) | (tmp << 16); | |
c8c2227e TS |
331 | } |
332 | ||
be24bb4f TS |
333 | if (GET_LMASK(t0) == 3) { |
334 | tmp = ldfun(GET_OFFSET(t0, -3)); | |
335 | t1 = (t1 & 0x00FFFFFF) | (tmp << 24); | |
c8c2227e | 336 | } |
be24bb4f | 337 | return (int32_t)t1; |
c8c2227e TS |
338 | } |
339 | ||
be24bb4f | 340 | void do_swl(target_ulong t0, target_ulong t1, int mem_idx) |
c8c2227e TS |
341 | { |
342 | #ifdef CONFIG_USER_ONLY | |
343 | #define stfun stb_raw | |
344 | #else | |
345 | void (*stfun)(target_ulong, int); | |
346 | ||
347 | switch (mem_idx) | |
348 | { | |
349 | case 0: stfun = stb_kernel; break; | |
350 | case 1: stfun = stb_super; break; | |
351 | default: | |
352 | case 2: stfun = stb_user; break; | |
353 | } | |
354 | #endif | |
be24bb4f | 355 | stfun(t0, (uint8_t)(t1 >> 24)); |
c8c2227e | 356 | |
be24bb4f TS |
357 | if (GET_LMASK(t0) <= 2) |
358 | stfun(GET_OFFSET(t0, 1), (uint8_t)(t1 >> 16)); | |
c8c2227e | 359 | |
be24bb4f TS |
360 | if (GET_LMASK(t0) <= 1) |
361 | stfun(GET_OFFSET(t0, 2), (uint8_t)(t1 >> 8)); | |
c8c2227e | 362 | |
be24bb4f TS |
363 | if (GET_LMASK(t0) == 0) |
364 | stfun(GET_OFFSET(t0, 3), (uint8_t)t1); | |
c8c2227e TS |
365 | } |
366 | ||
be24bb4f | 367 | void do_swr(target_ulong t0, target_ulong t1, int mem_idx) |
c8c2227e TS |
368 | { |
369 | #ifdef CONFIG_USER_ONLY | |
370 | #define stfun stb_raw | |
371 | #else | |
372 | void (*stfun)(target_ulong, int); | |
373 | ||
374 | switch (mem_idx) | |
375 | { | |
376 | case 0: stfun = stb_kernel; break; | |
377 | case 1: stfun = stb_super; break; | |
378 | default: | |
379 | case 2: stfun = stb_user; break; | |
380 | } | |
381 | #endif | |
be24bb4f | 382 | stfun(t0, (uint8_t)t1); |
c8c2227e | 383 | |
be24bb4f TS |
384 | if (GET_LMASK(t0) >= 1) |
385 | stfun(GET_OFFSET(t0, -1), (uint8_t)(t1 >> 8)); | |
c8c2227e | 386 | |
be24bb4f TS |
387 | if (GET_LMASK(t0) >= 2) |
388 | stfun(GET_OFFSET(t0, -2), (uint8_t)(t1 >> 16)); | |
c8c2227e | 389 | |
be24bb4f TS |
390 | if (GET_LMASK(t0) == 3) |
391 | stfun(GET_OFFSET(t0, -3), (uint8_t)(t1 >> 24)); | |
c8c2227e TS |
392 | } |
393 | ||
394 | #if defined(TARGET_MIPS64) | |
395 | /* "half" load and stores. We must do the memory access inline, | |
396 | or fault handling won't work. */ | |
397 | ||
398 | #ifdef TARGET_WORDS_BIGENDIAN | |
399 | #define GET_LMASK64(v) ((v) & 7) | |
400 | #else | |
401 | #define GET_LMASK64(v) (((v) & 7) ^ 7) | |
402 | #endif | |
403 | ||
be24bb4f | 404 | target_ulong do_ldl(target_ulong t0, target_ulong t1, int mem_idx) |
c8c2227e TS |
405 | { |
406 | uint64_t tmp; | |
407 | ||
408 | #ifdef CONFIG_USER_ONLY | |
409 | #define ldfun ldub_raw | |
410 | #else | |
be24bb4f | 411 | int (*ldfun)(target_ulong); |
c8c2227e TS |
412 | |
413 | switch (mem_idx) | |
414 | { | |
415 | case 0: ldfun = ldub_kernel; break; | |
416 | case 1: ldfun = ldub_super; break; | |
417 | default: | |
418 | case 2: ldfun = ldub_user; break; | |
419 | } | |
420 | #endif | |
be24bb4f TS |
421 | tmp = ldfun(t0); |
422 | t1 = (t1 & 0x00FFFFFFFFFFFFFFULL) | (tmp << 56); | |
c8c2227e | 423 | |
be24bb4f TS |
424 | if (GET_LMASK64(t0) <= 6) { |
425 | tmp = ldfun(GET_OFFSET(t0, 1)); | |
426 | t1 = (t1 & 0xFF00FFFFFFFFFFFFULL) | (tmp << 48); | |
c8c2227e TS |
427 | } |
428 | ||
be24bb4f TS |
429 | if (GET_LMASK64(t0) <= 5) { |
430 | tmp = ldfun(GET_OFFSET(t0, 2)); | |
431 | t1 = (t1 & 0xFFFF00FFFFFFFFFFULL) | (tmp << 40); | |
c8c2227e TS |
432 | } |
433 | ||
be24bb4f TS |
434 | if (GET_LMASK64(t0) <= 4) { |
435 | tmp = ldfun(GET_OFFSET(t0, 3)); | |
436 | t1 = (t1 & 0xFFFFFF00FFFFFFFFULL) | (tmp << 32); | |
c8c2227e TS |
437 | } |
438 | ||
be24bb4f TS |
439 | if (GET_LMASK64(t0) <= 3) { |
440 | tmp = ldfun(GET_OFFSET(t0, 4)); | |
441 | t1 = (t1 & 0xFFFFFFFF00FFFFFFULL) | (tmp << 24); | |
c8c2227e TS |
442 | } |
443 | ||
be24bb4f TS |
444 | if (GET_LMASK64(t0) <= 2) { |
445 | tmp = ldfun(GET_OFFSET(t0, 5)); | |
446 | t1 = (t1 & 0xFFFFFFFFFF00FFFFULL) | (tmp << 16); | |
c8c2227e TS |
447 | } |
448 | ||
be24bb4f TS |
449 | if (GET_LMASK64(t0) <= 1) { |
450 | tmp = ldfun(GET_OFFSET(t0, 6)); | |
451 | t1 = (t1 & 0xFFFFFFFFFFFF00FFULL) | (tmp << 8); | |
c8c2227e TS |
452 | } |
453 | ||
be24bb4f TS |
454 | if (GET_LMASK64(t0) == 0) { |
455 | tmp = ldfun(GET_OFFSET(t0, 7)); | |
456 | t1 = (t1 & 0xFFFFFFFFFFFFFF00ULL) | tmp; | |
c8c2227e | 457 | } |
be24bb4f TS |
458 | |
459 | return t1; | |
c8c2227e TS |
460 | } |
461 | ||
be24bb4f | 462 | target_ulong do_ldr(target_ulong t0, target_ulong t1, int mem_idx) |
c8c2227e TS |
463 | { |
464 | uint64_t tmp; | |
465 | ||
466 | #ifdef CONFIG_USER_ONLY | |
467 | #define ldfun ldub_raw | |
468 | #else | |
be24bb4f | 469 | int (*ldfun)(target_ulong); |
c8c2227e TS |
470 | |
471 | switch (mem_idx) | |
472 | { | |
473 | case 0: ldfun = ldub_kernel; break; | |
474 | case 1: ldfun = ldub_super; break; | |
475 | default: | |
476 | case 2: ldfun = ldub_user; break; | |
477 | } | |
478 | #endif | |
be24bb4f TS |
479 | tmp = ldfun(t0); |
480 | t1 = (t1 & 0xFFFFFFFFFFFFFF00ULL) | tmp; | |
c8c2227e | 481 | |
be24bb4f TS |
482 | if (GET_LMASK64(t0) >= 1) { |
483 | tmp = ldfun(GET_OFFSET(t0, -1)); | |
484 | t1 = (t1 & 0xFFFFFFFFFFFF00FFULL) | (tmp << 8); | |
c8c2227e TS |
485 | } |
486 | ||
be24bb4f TS |
487 | if (GET_LMASK64(t0) >= 2) { |
488 | tmp = ldfun(GET_OFFSET(t0, -2)); | |
489 | t1 = (t1 & 0xFFFFFFFFFF00FFFFULL) | (tmp << 16); | |
c8c2227e TS |
490 | } |
491 | ||
be24bb4f TS |
492 | if (GET_LMASK64(t0) >= 3) { |
493 | tmp = ldfun(GET_OFFSET(t0, -3)); | |
494 | t1 = (t1 & 0xFFFFFFFF00FFFFFFULL) | (tmp << 24); | |
c8c2227e TS |
495 | } |
496 | ||
be24bb4f TS |
497 | if (GET_LMASK64(t0) >= 4) { |
498 | tmp = ldfun(GET_OFFSET(t0, -4)); | |
499 | t1 = (t1 & 0xFFFFFF00FFFFFFFFULL) | (tmp << 32); | |
c8c2227e TS |
500 | } |
501 | ||
be24bb4f TS |
502 | if (GET_LMASK64(t0) >= 5) { |
503 | tmp = ldfun(GET_OFFSET(t0, -5)); | |
504 | t1 = (t1 & 0xFFFF00FFFFFFFFFFULL) | (tmp << 40); | |
c8c2227e TS |
505 | } |
506 | ||
be24bb4f TS |
507 | if (GET_LMASK64(t0) >= 6) { |
508 | tmp = ldfun(GET_OFFSET(t0, -6)); | |
509 | t1 = (t1 & 0xFF00FFFFFFFFFFFFULL) | (tmp << 48); | |
c8c2227e TS |
510 | } |
511 | ||
be24bb4f TS |
512 | if (GET_LMASK64(t0) == 7) { |
513 | tmp = ldfun(GET_OFFSET(t0, -7)); | |
514 | t1 = (t1 & 0x00FFFFFFFFFFFFFFULL) | (tmp << 56); | |
c8c2227e | 515 | } |
be24bb4f TS |
516 | |
517 | return t1; | |
c8c2227e TS |
518 | } |
519 | ||
be24bb4f | 520 | void do_sdl(target_ulong t0, target_ulong t1, int mem_idx) |
c8c2227e TS |
521 | { |
522 | #ifdef CONFIG_USER_ONLY | |
523 | #define stfun stb_raw | |
524 | #else | |
525 | void (*stfun)(target_ulong, int); | |
526 | ||
527 | switch (mem_idx) | |
528 | { | |
529 | case 0: stfun = stb_kernel; break; | |
530 | case 1: stfun = stb_super; break; | |
531 | default: | |
532 | case 2: stfun = stb_user; break; | |
533 | } | |
534 | #endif | |
be24bb4f | 535 | stfun(t0, (uint8_t)(t1 >> 56)); |
c8c2227e | 536 | |
be24bb4f TS |
537 | if (GET_LMASK64(t0) <= 6) |
538 | stfun(GET_OFFSET(t0, 1), (uint8_t)(t1 >> 48)); | |
c8c2227e | 539 | |
be24bb4f TS |
540 | if (GET_LMASK64(t0) <= 5) |
541 | stfun(GET_OFFSET(t0, 2), (uint8_t)(t1 >> 40)); | |
c8c2227e | 542 | |
be24bb4f TS |
543 | if (GET_LMASK64(t0) <= 4) |
544 | stfun(GET_OFFSET(t0, 3), (uint8_t)(t1 >> 32)); | |
c8c2227e | 545 | |
be24bb4f TS |
546 | if (GET_LMASK64(t0) <= 3) |
547 | stfun(GET_OFFSET(t0, 4), (uint8_t)(t1 >> 24)); | |
c8c2227e | 548 | |
be24bb4f TS |
549 | if (GET_LMASK64(t0) <= 2) |
550 | stfun(GET_OFFSET(t0, 5), (uint8_t)(t1 >> 16)); | |
c8c2227e | 551 | |
be24bb4f TS |
552 | if (GET_LMASK64(t0) <= 1) |
553 | stfun(GET_OFFSET(t0, 6), (uint8_t)(t1 >> 8)); | |
c8c2227e | 554 | |
be24bb4f TS |
555 | if (GET_LMASK64(t0) <= 0) |
556 | stfun(GET_OFFSET(t0, 7), (uint8_t)t1); | |
c8c2227e TS |
557 | } |
558 | ||
be24bb4f | 559 | void do_sdr(target_ulong t0, target_ulong t1, int mem_idx) |
c8c2227e TS |
560 | { |
561 | #ifdef CONFIG_USER_ONLY | |
562 | #define stfun stb_raw | |
563 | #else | |
564 | void (*stfun)(target_ulong, int); | |
565 | ||
566 | switch (mem_idx) | |
567 | { | |
568 | case 0: stfun = stb_kernel; break; | |
569 | case 1: stfun = stb_super; break; | |
570 | default: | |
571 | case 2: stfun = stb_user; break; | |
572 | } | |
573 | #endif | |
be24bb4f | 574 | stfun(t0, (uint8_t)t1); |
c8c2227e | 575 | |
be24bb4f TS |
576 | if (GET_LMASK64(t0) >= 1) |
577 | stfun(GET_OFFSET(t0, -1), (uint8_t)(t1 >> 8)); | |
c8c2227e | 578 | |
be24bb4f TS |
579 | if (GET_LMASK64(t0) >= 2) |
580 | stfun(GET_OFFSET(t0, -2), (uint8_t)(t1 >> 16)); | |
c8c2227e | 581 | |
be24bb4f TS |
582 | if (GET_LMASK64(t0) >= 3) |
583 | stfun(GET_OFFSET(t0, -3), (uint8_t)(t1 >> 24)); | |
c8c2227e | 584 | |
be24bb4f TS |
585 | if (GET_LMASK64(t0) >= 4) |
586 | stfun(GET_OFFSET(t0, -4), (uint8_t)(t1 >> 32)); | |
c8c2227e | 587 | |
be24bb4f TS |
588 | if (GET_LMASK64(t0) >= 5) |
589 | stfun(GET_OFFSET(t0, -5), (uint8_t)(t1 >> 40)); | |
c8c2227e | 590 | |
be24bb4f TS |
591 | if (GET_LMASK64(t0) >= 6) |
592 | stfun(GET_OFFSET(t0, -6), (uint8_t)(t1 >> 48)); | |
c8c2227e | 593 | |
be24bb4f TS |
594 | if (GET_LMASK64(t0) == 7) |
595 | stfun(GET_OFFSET(t0, -7), (uint8_t)(t1 >> 56)); | |
c8c2227e TS |
596 | } |
597 | #endif /* TARGET_MIPS64 */ | |
598 | ||
0eaef5aa | 599 | #ifndef CONFIG_USER_ONLY |
6af0bf9c | 600 | /* CP0 helpers */ |
1a3fd9c3 | 601 | target_ulong do_mfc0_mvpcontrol (void) |
f1aa6320 | 602 | { |
be24bb4f | 603 | return env->mvp->CP0_MVPControl; |
f1aa6320 TS |
604 | } |
605 | ||
1a3fd9c3 | 606 | target_ulong do_mfc0_mvpconf0 (void) |
f1aa6320 | 607 | { |
be24bb4f | 608 | return env->mvp->CP0_MVPConf0; |
f1aa6320 TS |
609 | } |
610 | ||
1a3fd9c3 | 611 | target_ulong do_mfc0_mvpconf1 (void) |
f1aa6320 | 612 | { |
be24bb4f | 613 | return env->mvp->CP0_MVPConf1; |
f1aa6320 TS |
614 | } |
615 | ||
1a3fd9c3 | 616 | target_ulong do_mfc0_random (void) |
6af0bf9c | 617 | { |
be24bb4f | 618 | return (int32_t)cpu_mips_get_random(env); |
873eb012 | 619 | } |
6af0bf9c | 620 | |
1a3fd9c3 | 621 | target_ulong do_mfc0_tcstatus (void) |
f1aa6320 | 622 | { |
b5dc7732 | 623 | return env->active_tc.CP0_TCStatus; |
f1aa6320 TS |
624 | } |
625 | ||
1a3fd9c3 | 626 | target_ulong do_mftc0_tcstatus(void) |
f1aa6320 TS |
627 | { |
628 | int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); | |
629 | ||
b5dc7732 TS |
630 | if (other_tc == env->current_tc) |
631 | return env->active_tc.CP0_TCStatus; | |
632 | else | |
633 | return env->tcs[other_tc].CP0_TCStatus; | |
f1aa6320 TS |
634 | } |
635 | ||
1a3fd9c3 | 636 | target_ulong do_mfc0_tcbind (void) |
f1aa6320 | 637 | { |
b5dc7732 | 638 | return env->active_tc.CP0_TCBind; |
f1aa6320 TS |
639 | } |
640 | ||
1a3fd9c3 | 641 | target_ulong do_mftc0_tcbind(void) |
f1aa6320 TS |
642 | { |
643 | int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); | |
644 | ||
b5dc7732 TS |
645 | if (other_tc == env->current_tc) |
646 | return env->active_tc.CP0_TCBind; | |
647 | else | |
648 | return env->tcs[other_tc].CP0_TCBind; | |
f1aa6320 TS |
649 | } |
650 | ||
1a3fd9c3 | 651 | target_ulong do_mfc0_tcrestart (void) |
f1aa6320 | 652 | { |
b5dc7732 | 653 | return env->active_tc.PC; |
f1aa6320 TS |
654 | } |
655 | ||
1a3fd9c3 | 656 | target_ulong do_mftc0_tcrestart(void) |
f1aa6320 TS |
657 | { |
658 | int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); | |
659 | ||
b5dc7732 TS |
660 | if (other_tc == env->current_tc) |
661 | return env->active_tc.PC; | |
662 | else | |
663 | return env->tcs[other_tc].PC; | |
f1aa6320 TS |
664 | } |
665 | ||
1a3fd9c3 | 666 | target_ulong do_mfc0_tchalt (void) |
f1aa6320 | 667 | { |
b5dc7732 | 668 | return env->active_tc.CP0_TCHalt; |
f1aa6320 TS |
669 | } |
670 | ||
1a3fd9c3 | 671 | target_ulong do_mftc0_tchalt(void) |
f1aa6320 TS |
672 | { |
673 | int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); | |
674 | ||
b5dc7732 TS |
675 | if (other_tc == env->current_tc) |
676 | return env->active_tc.CP0_TCHalt; | |
677 | else | |
678 | return env->tcs[other_tc].CP0_TCHalt; | |
f1aa6320 TS |
679 | } |
680 | ||
1a3fd9c3 | 681 | target_ulong do_mfc0_tccontext (void) |
f1aa6320 | 682 | { |
b5dc7732 | 683 | return env->active_tc.CP0_TCContext; |
f1aa6320 TS |
684 | } |
685 | ||
1a3fd9c3 | 686 | target_ulong do_mftc0_tccontext(void) |
f1aa6320 TS |
687 | { |
688 | int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); | |
689 | ||
b5dc7732 TS |
690 | if (other_tc == env->current_tc) |
691 | return env->active_tc.CP0_TCContext; | |
692 | else | |
693 | return env->tcs[other_tc].CP0_TCContext; | |
f1aa6320 TS |
694 | } |
695 | ||
1a3fd9c3 | 696 | target_ulong do_mfc0_tcschedule (void) |
f1aa6320 | 697 | { |
b5dc7732 | 698 | return env->active_tc.CP0_TCSchedule; |
f1aa6320 TS |
699 | } |
700 | ||
1a3fd9c3 | 701 | target_ulong do_mftc0_tcschedule(void) |
f1aa6320 TS |
702 | { |
703 | int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); | |
704 | ||
b5dc7732 TS |
705 | if (other_tc == env->current_tc) |
706 | return env->active_tc.CP0_TCSchedule; | |
707 | else | |
708 | return env->tcs[other_tc].CP0_TCSchedule; | |
f1aa6320 TS |
709 | } |
710 | ||
1a3fd9c3 | 711 | target_ulong do_mfc0_tcschefback (void) |
f1aa6320 | 712 | { |
b5dc7732 | 713 | return env->active_tc.CP0_TCScheFBack; |
f1aa6320 TS |
714 | } |
715 | ||
1a3fd9c3 | 716 | target_ulong do_mftc0_tcschefback(void) |
f1aa6320 TS |
717 | { |
718 | int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); | |
719 | ||
b5dc7732 TS |
720 | if (other_tc == env->current_tc) |
721 | return env->active_tc.CP0_TCScheFBack; | |
722 | else | |
723 | return env->tcs[other_tc].CP0_TCScheFBack; | |
f1aa6320 TS |
724 | } |
725 | ||
1a3fd9c3 | 726 | target_ulong do_mfc0_count (void) |
873eb012 | 727 | { |
be24bb4f | 728 | return (int32_t)cpu_mips_get_count(env); |
6af0bf9c FB |
729 | } |
730 | ||
1a3fd9c3 | 731 | target_ulong do_mftc0_entryhi(void) |
f1aa6320 TS |
732 | { |
733 | int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); | |
b5dc7732 | 734 | int32_t tcstatus; |
f1aa6320 | 735 | |
b5dc7732 TS |
736 | if (other_tc == env->current_tc) |
737 | tcstatus = env->active_tc.CP0_TCStatus; | |
738 | else | |
739 | tcstatus = env->tcs[other_tc].CP0_TCStatus; | |
740 | ||
741 | return (env->CP0_EntryHi & ~0xff) | (tcstatus & 0xff); | |
f1aa6320 TS |
742 | } |
743 | ||
1a3fd9c3 | 744 | target_ulong do_mftc0_status(void) |
f1aa6320 TS |
745 | { |
746 | int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); | |
1a3fd9c3 | 747 | target_ulong t0; |
b5dc7732 TS |
748 | int32_t tcstatus; |
749 | ||
750 | if (other_tc == env->current_tc) | |
751 | tcstatus = env->active_tc.CP0_TCStatus; | |
752 | else | |
753 | tcstatus = env->tcs[other_tc].CP0_TCStatus; | |
f1aa6320 | 754 | |
be24bb4f TS |
755 | t0 = env->CP0_Status & ~0xf1000018; |
756 | t0 |= tcstatus & (0xf << CP0TCSt_TCU0); | |
757 | t0 |= (tcstatus & (1 << CP0TCSt_TMX)) >> (CP0TCSt_TMX - CP0St_MX); | |
758 | t0 |= (tcstatus & (0x3 << CP0TCSt_TKSU)) >> (CP0TCSt_TKSU - CP0St_KSU); | |
759 | ||
760 | return t0; | |
f1aa6320 TS |
761 | } |
762 | ||
1a3fd9c3 | 763 | target_ulong do_mfc0_lladdr (void) |
f1aa6320 | 764 | { |
be24bb4f | 765 | return (int32_t)env->CP0_LLAddr >> 4; |
f1aa6320 TS |
766 | } |
767 | ||
1a3fd9c3 | 768 | target_ulong do_mfc0_watchlo (uint32_t sel) |
f1aa6320 | 769 | { |
be24bb4f | 770 | return (int32_t)env->CP0_WatchLo[sel]; |
f1aa6320 TS |
771 | } |
772 | ||
1a3fd9c3 | 773 | target_ulong do_mfc0_watchhi (uint32_t sel) |
f1aa6320 | 774 | { |
be24bb4f | 775 | return env->CP0_WatchHi[sel]; |
f1aa6320 TS |
776 | } |
777 | ||
1a3fd9c3 | 778 | target_ulong do_mfc0_debug (void) |
f1aa6320 | 779 | { |
1a3fd9c3 | 780 | target_ulong t0 = env->CP0_Debug; |
f1aa6320 | 781 | if (env->hflags & MIPS_HFLAG_DM) |
be24bb4f TS |
782 | t0 |= 1 << CP0DB_DM; |
783 | ||
784 | return t0; | |
f1aa6320 TS |
785 | } |
786 | ||
1a3fd9c3 | 787 | target_ulong do_mftc0_debug(void) |
f1aa6320 TS |
788 | { |
789 | int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); | |
b5dc7732 TS |
790 | int32_t tcstatus; |
791 | ||
792 | if (other_tc == env->current_tc) | |
793 | tcstatus = env->active_tc.CP0_Debug_tcstatus; | |
794 | else | |
795 | tcstatus = env->tcs[other_tc].CP0_Debug_tcstatus; | |
f1aa6320 TS |
796 | |
797 | /* XXX: Might be wrong, check with EJTAG spec. */ | |
be24bb4f | 798 | return (env->CP0_Debug & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) | |
b5dc7732 | 799 | (tcstatus & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt))); |
f1aa6320 TS |
800 | } |
801 | ||
802 | #if defined(TARGET_MIPS64) | |
1a3fd9c3 | 803 | target_ulong do_dmfc0_tcrestart (void) |
f1aa6320 | 804 | { |
b5dc7732 | 805 | return env->active_tc.PC; |
f1aa6320 TS |
806 | } |
807 | ||
1a3fd9c3 | 808 | target_ulong do_dmfc0_tchalt (void) |
f1aa6320 | 809 | { |
b5dc7732 | 810 | return env->active_tc.CP0_TCHalt; |
f1aa6320 TS |
811 | } |
812 | ||
1a3fd9c3 | 813 | target_ulong do_dmfc0_tccontext (void) |
f1aa6320 | 814 | { |
b5dc7732 | 815 | return env->active_tc.CP0_TCContext; |
f1aa6320 TS |
816 | } |
817 | ||
1a3fd9c3 | 818 | target_ulong do_dmfc0_tcschedule (void) |
f1aa6320 | 819 | { |
b5dc7732 | 820 | return env->active_tc.CP0_TCSchedule; |
f1aa6320 TS |
821 | } |
822 | ||
1a3fd9c3 | 823 | target_ulong do_dmfc0_tcschefback (void) |
f1aa6320 | 824 | { |
b5dc7732 | 825 | return env->active_tc.CP0_TCScheFBack; |
f1aa6320 TS |
826 | } |
827 | ||
1a3fd9c3 | 828 | target_ulong do_dmfc0_lladdr (void) |
f1aa6320 | 829 | { |
be24bb4f | 830 | return env->CP0_LLAddr >> 4; |
f1aa6320 TS |
831 | } |
832 | ||
1a3fd9c3 | 833 | target_ulong do_dmfc0_watchlo (uint32_t sel) |
f1aa6320 | 834 | { |
be24bb4f | 835 | return env->CP0_WatchLo[sel]; |
f1aa6320 TS |
836 | } |
837 | #endif /* TARGET_MIPS64 */ | |
838 | ||
be24bb4f | 839 | void do_mtc0_index (target_ulong t0) |
f1aa6320 TS |
840 | { |
841 | int num = 1; | |
842 | unsigned int tmp = env->tlb->nb_tlb; | |
843 | ||
844 | do { | |
845 | tmp >>= 1; | |
846 | num <<= 1; | |
847 | } while (tmp); | |
be24bb4f | 848 | env->CP0_Index = (env->CP0_Index & 0x80000000) | (t0 & (num - 1)); |
f1aa6320 TS |
849 | } |
850 | ||
be24bb4f | 851 | void do_mtc0_mvpcontrol (target_ulong t0) |
f1aa6320 TS |
852 | { |
853 | uint32_t mask = 0; | |
854 | uint32_t newval; | |
855 | ||
856 | if (env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) | |
857 | mask |= (1 << CP0MVPCo_CPA) | (1 << CP0MVPCo_VPC) | | |
858 | (1 << CP0MVPCo_EVP); | |
859 | if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC)) | |
860 | mask |= (1 << CP0MVPCo_STLB); | |
be24bb4f | 861 | newval = (env->mvp->CP0_MVPControl & ~mask) | (t0 & mask); |
f1aa6320 TS |
862 | |
863 | // TODO: Enable/disable shared TLB, enable/disable VPEs. | |
864 | ||
865 | env->mvp->CP0_MVPControl = newval; | |
866 | } | |
867 | ||
be24bb4f | 868 | void do_mtc0_vpecontrol (target_ulong t0) |
f1aa6320 TS |
869 | { |
870 | uint32_t mask; | |
871 | uint32_t newval; | |
872 | ||
873 | mask = (1 << CP0VPECo_YSI) | (1 << CP0VPECo_GSI) | | |
874 | (1 << CP0VPECo_TE) | (0xff << CP0VPECo_TargTC); | |
be24bb4f | 875 | newval = (env->CP0_VPEControl & ~mask) | (t0 & mask); |
f1aa6320 TS |
876 | |
877 | /* Yield scheduler intercept not implemented. */ | |
878 | /* Gating storage scheduler intercept not implemented. */ | |
879 | ||
880 | // TODO: Enable/disable TCs. | |
881 | ||
882 | env->CP0_VPEControl = newval; | |
883 | } | |
884 | ||
be24bb4f | 885 | void do_mtc0_vpeconf0 (target_ulong t0) |
f1aa6320 TS |
886 | { |
887 | uint32_t mask = 0; | |
888 | uint32_t newval; | |
889 | ||
890 | if (env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) { | |
891 | if (env->CP0_VPEConf0 & (1 << CP0VPEC0_VPA)) | |
892 | mask |= (0xff << CP0VPEC0_XTC); | |
893 | mask |= (1 << CP0VPEC0_MVP) | (1 << CP0VPEC0_VPA); | |
894 | } | |
be24bb4f | 895 | newval = (env->CP0_VPEConf0 & ~mask) | (t0 & mask); |
f1aa6320 TS |
896 | |
897 | // TODO: TC exclusive handling due to ERL/EXL. | |
898 | ||
899 | env->CP0_VPEConf0 = newval; | |
900 | } | |
901 | ||
be24bb4f | 902 | void do_mtc0_vpeconf1 (target_ulong t0) |
f1aa6320 TS |
903 | { |
904 | uint32_t mask = 0; | |
905 | uint32_t newval; | |
906 | ||
907 | if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC)) | |
908 | mask |= (0xff << CP0VPEC1_NCX) | (0xff << CP0VPEC1_NCP2) | | |
909 | (0xff << CP0VPEC1_NCP1); | |
be24bb4f | 910 | newval = (env->CP0_VPEConf1 & ~mask) | (t0 & mask); |
f1aa6320 TS |
911 | |
912 | /* UDI not implemented. */ | |
913 | /* CP2 not implemented. */ | |
914 | ||
915 | // TODO: Handle FPU (CP1) binding. | |
916 | ||
917 | env->CP0_VPEConf1 = newval; | |
918 | } | |
919 | ||
be24bb4f | 920 | void do_mtc0_yqmask (target_ulong t0) |
f1aa6320 TS |
921 | { |
922 | /* Yield qualifier inputs not implemented. */ | |
923 | env->CP0_YQMask = 0x00000000; | |
924 | } | |
925 | ||
be24bb4f | 926 | void do_mtc0_vpeopt (target_ulong t0) |
f1aa6320 | 927 | { |
be24bb4f | 928 | env->CP0_VPEOpt = t0 & 0x0000ffff; |
f1aa6320 TS |
929 | } |
930 | ||
be24bb4f | 931 | void do_mtc0_entrylo0 (target_ulong t0) |
f1aa6320 TS |
932 | { |
933 | /* Large physaddr (PABITS) not implemented */ | |
934 | /* 1k pages not implemented */ | |
be24bb4f | 935 | env->CP0_EntryLo0 = t0 & 0x3FFFFFFF; |
f1aa6320 TS |
936 | } |
937 | ||
be24bb4f | 938 | void do_mtc0_tcstatus (target_ulong t0) |
f1aa6320 TS |
939 | { |
940 | uint32_t mask = env->CP0_TCStatus_rw_bitmask; | |
941 | uint32_t newval; | |
942 | ||
b5dc7732 | 943 | newval = (env->active_tc.CP0_TCStatus & ~mask) | (t0 & mask); |
f1aa6320 TS |
944 | |
945 | // TODO: Sync with CP0_Status. | |
946 | ||
b5dc7732 | 947 | env->active_tc.CP0_TCStatus = newval; |
f1aa6320 TS |
948 | } |
949 | ||
be24bb4f | 950 | void do_mttc0_tcstatus (target_ulong t0) |
f1aa6320 TS |
951 | { |
952 | int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); | |
953 | ||
954 | // TODO: Sync with CP0_Status. | |
955 | ||
b5dc7732 TS |
956 | if (other_tc == env->current_tc) |
957 | env->active_tc.CP0_TCStatus = t0; | |
958 | else | |
959 | env->tcs[other_tc].CP0_TCStatus = t0; | |
f1aa6320 TS |
960 | } |
961 | ||
be24bb4f | 962 | void do_mtc0_tcbind (target_ulong t0) |
f1aa6320 TS |
963 | { |
964 | uint32_t mask = (1 << CP0TCBd_TBE); | |
965 | uint32_t newval; | |
966 | ||
967 | if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC)) | |
968 | mask |= (1 << CP0TCBd_CurVPE); | |
b5dc7732 TS |
969 | newval = (env->active_tc.CP0_TCBind & ~mask) | (t0 & mask); |
970 | env->active_tc.CP0_TCBind = newval; | |
f1aa6320 TS |
971 | } |
972 | ||
be24bb4f | 973 | void do_mttc0_tcbind (target_ulong t0) |
f1aa6320 TS |
974 | { |
975 | int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); | |
976 | uint32_t mask = (1 << CP0TCBd_TBE); | |
977 | uint32_t newval; | |
978 | ||
979 | if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC)) | |
980 | mask |= (1 << CP0TCBd_CurVPE); | |
b5dc7732 TS |
981 | if (other_tc == env->current_tc) { |
982 | newval = (env->active_tc.CP0_TCBind & ~mask) | (t0 & mask); | |
983 | env->active_tc.CP0_TCBind = newval; | |
984 | } else { | |
985 | newval = (env->tcs[other_tc].CP0_TCBind & ~mask) | (t0 & mask); | |
986 | env->tcs[other_tc].CP0_TCBind = newval; | |
987 | } | |
f1aa6320 TS |
988 | } |
989 | ||
be24bb4f | 990 | void do_mtc0_tcrestart (target_ulong t0) |
f1aa6320 | 991 | { |
b5dc7732 TS |
992 | env->active_tc.PC = t0; |
993 | env->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS); | |
f1aa6320 TS |
994 | env->CP0_LLAddr = 0ULL; |
995 | /* MIPS16 not implemented. */ | |
996 | } | |
997 | ||
be24bb4f | 998 | void do_mttc0_tcrestart (target_ulong t0) |
f1aa6320 TS |
999 | { |
1000 | int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); | |
1001 | ||
b5dc7732 TS |
1002 | if (other_tc == env->current_tc) { |
1003 | env->active_tc.PC = t0; | |
1004 | env->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS); | |
1005 | env->CP0_LLAddr = 0ULL; | |
1006 | /* MIPS16 not implemented. */ | |
1007 | } else { | |
1008 | env->tcs[other_tc].PC = t0; | |
1009 | env->tcs[other_tc].CP0_TCStatus &= ~(1 << CP0TCSt_TDS); | |
1010 | env->CP0_LLAddr = 0ULL; | |
1011 | /* MIPS16 not implemented. */ | |
1012 | } | |
f1aa6320 TS |
1013 | } |
1014 | ||
be24bb4f | 1015 | void do_mtc0_tchalt (target_ulong t0) |
f1aa6320 | 1016 | { |
b5dc7732 | 1017 | env->active_tc.CP0_TCHalt = t0 & 0x1; |
f1aa6320 TS |
1018 | |
1019 | // TODO: Halt TC / Restart (if allocated+active) TC. | |
1020 | } | |
1021 | ||
be24bb4f | 1022 | void do_mttc0_tchalt (target_ulong t0) |
f1aa6320 TS |
1023 | { |
1024 | int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); | |
1025 | ||
1026 | // TODO: Halt TC / Restart (if allocated+active) TC. | |
1027 | ||
b5dc7732 TS |
1028 | if (other_tc == env->current_tc) |
1029 | env->active_tc.CP0_TCHalt = t0; | |
1030 | else | |
1031 | env->tcs[other_tc].CP0_TCHalt = t0; | |
f1aa6320 TS |
1032 | } |
1033 | ||
be24bb4f | 1034 | void do_mtc0_tccontext (target_ulong t0) |
f1aa6320 | 1035 | { |
b5dc7732 | 1036 | env->active_tc.CP0_TCContext = t0; |
f1aa6320 TS |
1037 | } |
1038 | ||
be24bb4f | 1039 | void do_mttc0_tccontext (target_ulong t0) |
f1aa6320 TS |
1040 | { |
1041 | int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); | |
1042 | ||
b5dc7732 TS |
1043 | if (other_tc == env->current_tc) |
1044 | env->active_tc.CP0_TCContext = t0; | |
1045 | else | |
1046 | env->tcs[other_tc].CP0_TCContext = t0; | |
f1aa6320 TS |
1047 | } |
1048 | ||
be24bb4f | 1049 | void do_mtc0_tcschedule (target_ulong t0) |
f1aa6320 | 1050 | { |
b5dc7732 | 1051 | env->active_tc.CP0_TCSchedule = t0; |
f1aa6320 TS |
1052 | } |
1053 | ||
be24bb4f | 1054 | void do_mttc0_tcschedule (target_ulong t0) |
f1aa6320 TS |
1055 | { |
1056 | int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); | |
1057 | ||
b5dc7732 TS |
1058 | if (other_tc == env->current_tc) |
1059 | env->active_tc.CP0_TCSchedule = t0; | |
1060 | else | |
1061 | env->tcs[other_tc].CP0_TCSchedule = t0; | |
f1aa6320 TS |
1062 | } |
1063 | ||
be24bb4f | 1064 | void do_mtc0_tcschefback (target_ulong t0) |
f1aa6320 | 1065 | { |
b5dc7732 | 1066 | env->active_tc.CP0_TCScheFBack = t0; |
f1aa6320 TS |
1067 | } |
1068 | ||
be24bb4f | 1069 | void do_mttc0_tcschefback (target_ulong t0) |
f1aa6320 TS |
1070 | { |
1071 | int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); | |
1072 | ||
b5dc7732 TS |
1073 | if (other_tc == env->current_tc) |
1074 | env->active_tc.CP0_TCScheFBack = t0; | |
1075 | else | |
1076 | env->tcs[other_tc].CP0_TCScheFBack = t0; | |
f1aa6320 TS |
1077 | } |
1078 | ||
be24bb4f | 1079 | void do_mtc0_entrylo1 (target_ulong t0) |
f1aa6320 TS |
1080 | { |
1081 | /* Large physaddr (PABITS) not implemented */ | |
1082 | /* 1k pages not implemented */ | |
be24bb4f | 1083 | env->CP0_EntryLo1 = t0 & 0x3FFFFFFF; |
f1aa6320 TS |
1084 | } |
1085 | ||
be24bb4f | 1086 | void do_mtc0_context (target_ulong t0) |
f1aa6320 | 1087 | { |
be24bb4f | 1088 | env->CP0_Context = (env->CP0_Context & 0x007FFFFF) | (t0 & ~0x007FFFFF); |
f1aa6320 TS |
1089 | } |
1090 | ||
be24bb4f | 1091 | void do_mtc0_pagemask (target_ulong t0) |
f1aa6320 TS |
1092 | { |
1093 | /* 1k pages not implemented */ | |
be24bb4f | 1094 | env->CP0_PageMask = t0 & (0x1FFFFFFF & (TARGET_PAGE_MASK << 1)); |
f1aa6320 TS |
1095 | } |
1096 | ||
be24bb4f | 1097 | void do_mtc0_pagegrain (target_ulong t0) |
f1aa6320 TS |
1098 | { |
1099 | /* SmartMIPS not implemented */ | |
1100 | /* Large physaddr (PABITS) not implemented */ | |
1101 | /* 1k pages not implemented */ | |
1102 | env->CP0_PageGrain = 0; | |
1103 | } | |
1104 | ||
be24bb4f | 1105 | void do_mtc0_wired (target_ulong t0) |
f1aa6320 | 1106 | { |
be24bb4f | 1107 | env->CP0_Wired = t0 % env->tlb->nb_tlb; |
f1aa6320 TS |
1108 | } |
1109 | ||
be24bb4f | 1110 | void do_mtc0_srsconf0 (target_ulong t0) |
f1aa6320 | 1111 | { |
be24bb4f | 1112 | env->CP0_SRSConf0 |= t0 & env->CP0_SRSConf0_rw_bitmask; |
f1aa6320 TS |
1113 | } |
1114 | ||
be24bb4f | 1115 | void do_mtc0_srsconf1 (target_ulong t0) |
f1aa6320 | 1116 | { |
be24bb4f | 1117 | env->CP0_SRSConf1 |= t0 & env->CP0_SRSConf1_rw_bitmask; |
f1aa6320 TS |
1118 | } |
1119 | ||
be24bb4f | 1120 | void do_mtc0_srsconf2 (target_ulong t0) |
f1aa6320 | 1121 | { |
be24bb4f | 1122 | env->CP0_SRSConf2 |= t0 & env->CP0_SRSConf2_rw_bitmask; |
f1aa6320 TS |
1123 | } |
1124 | ||
be24bb4f | 1125 | void do_mtc0_srsconf3 (target_ulong t0) |
f1aa6320 | 1126 | { |
be24bb4f | 1127 | env->CP0_SRSConf3 |= t0 & env->CP0_SRSConf3_rw_bitmask; |
f1aa6320 TS |
1128 | } |
1129 | ||
be24bb4f | 1130 | void do_mtc0_srsconf4 (target_ulong t0) |
f1aa6320 | 1131 | { |
be24bb4f | 1132 | env->CP0_SRSConf4 |= t0 & env->CP0_SRSConf4_rw_bitmask; |
f1aa6320 TS |
1133 | } |
1134 | ||
be24bb4f | 1135 | void do_mtc0_hwrena (target_ulong t0) |
f1aa6320 | 1136 | { |
be24bb4f | 1137 | env->CP0_HWREna = t0 & 0x0000000F; |
f1aa6320 TS |
1138 | } |
1139 | ||
be24bb4f | 1140 | void do_mtc0_count (target_ulong t0) |
f1aa6320 | 1141 | { |
be24bb4f | 1142 | cpu_mips_store_count(env, t0); |
f1aa6320 TS |
1143 | } |
1144 | ||
be24bb4f | 1145 | void do_mtc0_entryhi (target_ulong t0) |
f1aa6320 TS |
1146 | { |
1147 | target_ulong old, val; | |
1148 | ||
1149 | /* 1k pages not implemented */ | |
be24bb4f | 1150 | val = t0 & ((TARGET_PAGE_MASK << 1) | 0xFF); |
f1aa6320 TS |
1151 | #if defined(TARGET_MIPS64) |
1152 | val &= env->SEGMask; | |
1153 | #endif | |
1154 | old = env->CP0_EntryHi; | |
1155 | env->CP0_EntryHi = val; | |
1156 | if (env->CP0_Config3 & (1 << CP0C3_MT)) { | |
b5dc7732 TS |
1157 | uint32_t tcst = env->active_tc.CP0_TCStatus & ~0xff; |
1158 | env->active_tc.CP0_TCStatus = tcst | (val & 0xff); | |
f1aa6320 TS |
1159 | } |
1160 | /* If the ASID changes, flush qemu's TLB. */ | |
1161 | if ((old & 0xFF) != (val & 0xFF)) | |
1162 | cpu_mips_tlb_flush(env, 1); | |
1163 | } | |
1164 | ||
be24bb4f | 1165 | void do_mttc0_entryhi(target_ulong t0) |
f1aa6320 TS |
1166 | { |
1167 | int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); | |
b5dc7732 | 1168 | int32_t tcstatus; |
f1aa6320 | 1169 | |
be24bb4f | 1170 | env->CP0_EntryHi = (env->CP0_EntryHi & 0xff) | (t0 & ~0xff); |
b5dc7732 TS |
1171 | if (other_tc == env->current_tc) { |
1172 | tcstatus = (env->active_tc.CP0_TCStatus & ~0xff) | (t0 & 0xff); | |
1173 | env->active_tc.CP0_TCStatus = tcstatus; | |
1174 | } else { | |
1175 | tcstatus = (env->tcs[other_tc].CP0_TCStatus & ~0xff) | (t0 & 0xff); | |
1176 | env->tcs[other_tc].CP0_TCStatus = tcstatus; | |
1177 | } | |
f1aa6320 TS |
1178 | } |
1179 | ||
be24bb4f | 1180 | void do_mtc0_compare (target_ulong t0) |
f1aa6320 | 1181 | { |
be24bb4f | 1182 | cpu_mips_store_compare(env, t0); |
f1aa6320 TS |
1183 | } |
1184 | ||
be24bb4f | 1185 | void do_mtc0_status (target_ulong t0) |
f1aa6320 TS |
1186 | { |
1187 | uint32_t val, old; | |
1188 | uint32_t mask = env->CP0_Status_rw_bitmask; | |
1189 | ||
be24bb4f | 1190 | val = t0 & mask; |
f1aa6320 TS |
1191 | old = env->CP0_Status; |
1192 | env->CP0_Status = (env->CP0_Status & ~mask) | val; | |
1193 | compute_hflags(env); | |
1194 | if (loglevel & CPU_LOG_EXEC) | |
1195 | do_mtc0_status_debug(old, val); | |
1196 | cpu_mips_update_irq(env); | |
1197 | } | |
1198 | ||
be24bb4f | 1199 | void do_mttc0_status(target_ulong t0) |
f1aa6320 TS |
1200 | { |
1201 | int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); | |
b5dc7732 | 1202 | int32_t tcstatus = env->tcs[other_tc].CP0_TCStatus; |
f1aa6320 | 1203 | |
be24bb4f TS |
1204 | env->CP0_Status = t0 & ~0xf1000018; |
1205 | tcstatus = (tcstatus & ~(0xf << CP0TCSt_TCU0)) | (t0 & (0xf << CP0St_CU0)); | |
1206 | tcstatus = (tcstatus & ~(1 << CP0TCSt_TMX)) | ((t0 & (1 << CP0St_MX)) << (CP0TCSt_TMX - CP0St_MX)); | |
1207 | tcstatus = (tcstatus & ~(0x3 << CP0TCSt_TKSU)) | ((t0 & (0x3 << CP0St_KSU)) << (CP0TCSt_TKSU - CP0St_KSU)); | |
b5dc7732 TS |
1208 | if (other_tc == env->current_tc) |
1209 | env->active_tc.CP0_TCStatus = tcstatus; | |
1210 | else | |
1211 | env->tcs[other_tc].CP0_TCStatus = tcstatus; | |
f1aa6320 TS |
1212 | } |
1213 | ||
be24bb4f | 1214 | void do_mtc0_intctl (target_ulong t0) |
f1aa6320 TS |
1215 | { |
1216 | /* vectored interrupts not implemented, no performance counters. */ | |
be24bb4f | 1217 | env->CP0_IntCtl = (env->CP0_IntCtl & ~0x000002e0) | (t0 & 0x000002e0); |
f1aa6320 TS |
1218 | } |
1219 | ||
be24bb4f | 1220 | void do_mtc0_srsctl (target_ulong t0) |
f1aa6320 TS |
1221 | { |
1222 | uint32_t mask = (0xf << CP0SRSCtl_ESS) | (0xf << CP0SRSCtl_PSS); | |
be24bb4f | 1223 | env->CP0_SRSCtl = (env->CP0_SRSCtl & ~mask) | (t0 & mask); |
f1aa6320 TS |
1224 | } |
1225 | ||
be24bb4f | 1226 | void do_mtc0_cause (target_ulong t0) |
f1aa6320 TS |
1227 | { |
1228 | uint32_t mask = 0x00C00300; | |
1229 | uint32_t old = env->CP0_Cause; | |
1230 | ||
1231 | if (env->insn_flags & ISA_MIPS32R2) | |
1232 | mask |= 1 << CP0Ca_DC; | |
1233 | ||
be24bb4f | 1234 | env->CP0_Cause = (env->CP0_Cause & ~mask) | (t0 & mask); |
f1aa6320 TS |
1235 | |
1236 | if ((old ^ env->CP0_Cause) & (1 << CP0Ca_DC)) { | |
1237 | if (env->CP0_Cause & (1 << CP0Ca_DC)) | |
1238 | cpu_mips_stop_count(env); | |
1239 | else | |
1240 | cpu_mips_start_count(env); | |
1241 | } | |
1242 | ||
1243 | /* Handle the software interrupt as an hardware one, as they | |
1244 | are very similar */ | |
be24bb4f | 1245 | if (t0 & CP0Ca_IP_mask) { |
f1aa6320 TS |
1246 | cpu_mips_update_irq(env); |
1247 | } | |
1248 | } | |
1249 | ||
be24bb4f | 1250 | void do_mtc0_ebase (target_ulong t0) |
f1aa6320 TS |
1251 | { |
1252 | /* vectored interrupts not implemented */ | |
1253 | /* Multi-CPU not implemented */ | |
be24bb4f | 1254 | env->CP0_EBase = 0x80000000 | (t0 & 0x3FFFF000); |
f1aa6320 TS |
1255 | } |
1256 | ||
be24bb4f | 1257 | void do_mtc0_config0 (target_ulong t0) |
f1aa6320 | 1258 | { |
be24bb4f | 1259 | env->CP0_Config0 = (env->CP0_Config0 & 0x81FFFFF8) | (t0 & 0x00000007); |
f1aa6320 TS |
1260 | } |
1261 | ||
be24bb4f | 1262 | void do_mtc0_config2 (target_ulong t0) |
f1aa6320 TS |
1263 | { |
1264 | /* tertiary/secondary caches not implemented */ | |
1265 | env->CP0_Config2 = (env->CP0_Config2 & 0x8FFF0FFF); | |
1266 | } | |
1267 | ||
be24bb4f | 1268 | void do_mtc0_watchlo (target_ulong t0, uint32_t sel) |
f1aa6320 TS |
1269 | { |
1270 | /* Watch exceptions for instructions, data loads, data stores | |
1271 | not implemented. */ | |
be24bb4f | 1272 | env->CP0_WatchLo[sel] = (t0 & ~0x7); |
f1aa6320 TS |
1273 | } |
1274 | ||
be24bb4f | 1275 | void do_mtc0_watchhi (target_ulong t0, uint32_t sel) |
f1aa6320 | 1276 | { |
be24bb4f TS |
1277 | env->CP0_WatchHi[sel] = (t0 & 0x40FF0FF8); |
1278 | env->CP0_WatchHi[sel] &= ~(env->CP0_WatchHi[sel] & t0 & 0x7); | |
f1aa6320 TS |
1279 | } |
1280 | ||
be24bb4f | 1281 | void do_mtc0_xcontext (target_ulong t0) |
f1aa6320 TS |
1282 | { |
1283 | target_ulong mask = (1ULL << (env->SEGBITS - 7)) - 1; | |
be24bb4f | 1284 | env->CP0_XContext = (env->CP0_XContext & mask) | (t0 & ~mask); |
f1aa6320 TS |
1285 | } |
1286 | ||
be24bb4f | 1287 | void do_mtc0_framemask (target_ulong t0) |
f1aa6320 | 1288 | { |
be24bb4f | 1289 | env->CP0_Framemask = t0; /* XXX */ |
f1aa6320 TS |
1290 | } |
1291 | ||
be24bb4f | 1292 | void do_mtc0_debug (target_ulong t0) |
f1aa6320 | 1293 | { |
be24bb4f TS |
1294 | env->CP0_Debug = (env->CP0_Debug & 0x8C03FC1F) | (t0 & 0x13300120); |
1295 | if (t0 & (1 << CP0DB_DM)) | |
f1aa6320 TS |
1296 | env->hflags |= MIPS_HFLAG_DM; |
1297 | else | |
1298 | env->hflags &= ~MIPS_HFLAG_DM; | |
1299 | } | |
1300 | ||
be24bb4f | 1301 | void do_mttc0_debug(target_ulong t0) |
f1aa6320 TS |
1302 | { |
1303 | int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); | |
b5dc7732 | 1304 | uint32_t val = t0 & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt)); |
f1aa6320 TS |
1305 | |
1306 | /* XXX: Might be wrong, check with EJTAG spec. */ | |
b5dc7732 TS |
1307 | if (other_tc == env->current_tc) |
1308 | env->active_tc.CP0_Debug_tcstatus = val; | |
1309 | else | |
1310 | env->tcs[other_tc].CP0_Debug_tcstatus = val; | |
f1aa6320 | 1311 | env->CP0_Debug = (env->CP0_Debug & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) | |
be24bb4f | 1312 | (t0 & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt))); |
f1aa6320 TS |
1313 | } |
1314 | ||
be24bb4f | 1315 | void do_mtc0_performance0 (target_ulong t0) |
f1aa6320 | 1316 | { |
be24bb4f | 1317 | env->CP0_Performance0 = t0 & 0x000007ff; |
f1aa6320 TS |
1318 | } |
1319 | ||
be24bb4f | 1320 | void do_mtc0_taglo (target_ulong t0) |
f1aa6320 | 1321 | { |
be24bb4f | 1322 | env->CP0_TagLo = t0 & 0xFFFFFCF6; |
f1aa6320 TS |
1323 | } |
1324 | ||
be24bb4f | 1325 | void do_mtc0_datalo (target_ulong t0) |
f1aa6320 | 1326 | { |
be24bb4f | 1327 | env->CP0_DataLo = t0; /* XXX */ |
f1aa6320 TS |
1328 | } |
1329 | ||
be24bb4f | 1330 | void do_mtc0_taghi (target_ulong t0) |
f1aa6320 | 1331 | { |
be24bb4f | 1332 | env->CP0_TagHi = t0; /* XXX */ |
f1aa6320 TS |
1333 | } |
1334 | ||
be24bb4f | 1335 | void do_mtc0_datahi (target_ulong t0) |
f1aa6320 | 1336 | { |
be24bb4f | 1337 | env->CP0_DataHi = t0; /* XXX */ |
f1aa6320 TS |
1338 | } |
1339 | ||
8c0fdd85 | 1340 | void do_mtc0_status_debug(uint32_t old, uint32_t val) |
6af0bf9c | 1341 | { |
f41c52f1 TS |
1342 | fprintf(logfile, "Status %08x (%08x) => %08x (%08x) Cause %08x", |
1343 | old, old & env->CP0_Cause & CP0Ca_IP_mask, | |
1344 | val, val & env->CP0_Cause & CP0Ca_IP_mask, | |
1345 | env->CP0_Cause); | |
623a930e TS |
1346 | switch (env->hflags & MIPS_HFLAG_KSU) { |
1347 | case MIPS_HFLAG_UM: fputs(", UM\n", logfile); break; | |
1348 | case MIPS_HFLAG_SM: fputs(", SM\n", logfile); break; | |
1349 | case MIPS_HFLAG_KM: fputs("\n", logfile); break; | |
1350 | default: cpu_abort(env, "Invalid MMU mode!\n"); break; | |
1351 | } | |
8c0fdd85 TS |
1352 | } |
1353 | ||
1354 | void do_mtc0_status_irqraise_debug(void) | |
1355 | { | |
1356 | fprintf(logfile, "Raise pending IRQs\n"); | |
6af0bf9c | 1357 | } |
f1aa6320 TS |
1358 | #endif /* !CONFIG_USER_ONLY */ |
1359 | ||
1360 | /* MIPS MT functions */ | |
be24bb4f | 1361 | target_ulong do_mftgpr(target_ulong t0, uint32_t sel) |
f1aa6320 TS |
1362 | { |
1363 | int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); | |
1364 | ||
b5dc7732 TS |
1365 | if (other_tc == env->current_tc) |
1366 | return env->active_tc.gpr[sel]; | |
1367 | else | |
1368 | return env->tcs[other_tc].gpr[sel]; | |
f1aa6320 TS |
1369 | } |
1370 | ||
be24bb4f | 1371 | target_ulong do_mftlo(target_ulong t0, uint32_t sel) |
f1aa6320 TS |
1372 | { |
1373 | int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); | |
1374 | ||
b5dc7732 TS |
1375 | if (other_tc == env->current_tc) |
1376 | return env->active_tc.LO[sel]; | |
1377 | else | |
1378 | return env->tcs[other_tc].LO[sel]; | |
f1aa6320 TS |
1379 | } |
1380 | ||
be24bb4f | 1381 | target_ulong do_mfthi(target_ulong t0, uint32_t sel) |
f1aa6320 TS |
1382 | { |
1383 | int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); | |
1384 | ||
b5dc7732 TS |
1385 | if (other_tc == env->current_tc) |
1386 | return env->active_tc.HI[sel]; | |
1387 | else | |
1388 | return env->tcs[other_tc].HI[sel]; | |
f1aa6320 TS |
1389 | } |
1390 | ||
be24bb4f | 1391 | target_ulong do_mftacx(target_ulong t0, uint32_t sel) |
f1aa6320 TS |
1392 | { |
1393 | int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); | |
1394 | ||
b5dc7732 TS |
1395 | if (other_tc == env->current_tc) |
1396 | return env->active_tc.ACX[sel]; | |
1397 | else | |
1398 | return env->tcs[other_tc].ACX[sel]; | |
f1aa6320 TS |
1399 | } |
1400 | ||
be24bb4f | 1401 | target_ulong do_mftdsp(target_ulong t0) |
f1aa6320 TS |
1402 | { |
1403 | int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); | |
1404 | ||
b5dc7732 TS |
1405 | if (other_tc == env->current_tc) |
1406 | return env->active_tc.DSPControl; | |
1407 | else | |
1408 | return env->tcs[other_tc].DSPControl; | |
f1aa6320 | 1409 | } |
6af0bf9c | 1410 | |
be24bb4f | 1411 | void do_mttgpr(target_ulong t0, uint32_t sel) |
f1aa6320 TS |
1412 | { |
1413 | int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); | |
1414 | ||
b5dc7732 TS |
1415 | if (other_tc == env->current_tc) |
1416 | env->active_tc.gpr[sel] = t0; | |
1417 | else | |
1418 | env->tcs[other_tc].gpr[sel] = t0; | |
f1aa6320 TS |
1419 | } |
1420 | ||
be24bb4f | 1421 | void do_mttlo(target_ulong t0, uint32_t sel) |
f1aa6320 TS |
1422 | { |
1423 | int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); | |
1424 | ||
b5dc7732 TS |
1425 | if (other_tc == env->current_tc) |
1426 | env->active_tc.LO[sel] = t0; | |
1427 | else | |
1428 | env->tcs[other_tc].LO[sel] = t0; | |
f1aa6320 TS |
1429 | } |
1430 | ||
be24bb4f | 1431 | void do_mtthi(target_ulong t0, uint32_t sel) |
f1aa6320 TS |
1432 | { |
1433 | int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); | |
1434 | ||
b5dc7732 TS |
1435 | if (other_tc == env->current_tc) |
1436 | env->active_tc.HI[sel] = t0; | |
1437 | else | |
1438 | env->tcs[other_tc].HI[sel] = t0; | |
f1aa6320 TS |
1439 | } |
1440 | ||
be24bb4f | 1441 | void do_mttacx(target_ulong t0, uint32_t sel) |
f1aa6320 TS |
1442 | { |
1443 | int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); | |
1444 | ||
b5dc7732 TS |
1445 | if (other_tc == env->current_tc) |
1446 | env->active_tc.ACX[sel] = t0; | |
1447 | else | |
1448 | env->tcs[other_tc].ACX[sel] = t0; | |
f1aa6320 TS |
1449 | } |
1450 | ||
be24bb4f | 1451 | void do_mttdsp(target_ulong t0) |
f1aa6320 TS |
1452 | { |
1453 | int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); | |
1454 | ||
b5dc7732 TS |
1455 | if (other_tc == env->current_tc) |
1456 | env->active_tc.DSPControl = t0; | |
1457 | else | |
1458 | env->tcs[other_tc].DSPControl = t0; | |
f1aa6320 TS |
1459 | } |
1460 | ||
1461 | /* MIPS MT functions */ | |
be24bb4f | 1462 | target_ulong do_dmt(target_ulong t0) |
f1aa6320 TS |
1463 | { |
1464 | // TODO | |
be24bb4f TS |
1465 | t0 = 0; |
1466 | // rt = t0 | |
1467 | ||
1468 | return t0; | |
f1aa6320 TS |
1469 | } |
1470 | ||
be24bb4f | 1471 | target_ulong do_emt(target_ulong t0) |
f1aa6320 TS |
1472 | { |
1473 | // TODO | |
be24bb4f TS |
1474 | t0 = 0; |
1475 | // rt = t0 | |
1476 | ||
1477 | return t0; | |
f1aa6320 TS |
1478 | } |
1479 | ||
be24bb4f | 1480 | target_ulong do_dvpe(target_ulong t0) |
f1aa6320 TS |
1481 | { |
1482 | // TODO | |
be24bb4f TS |
1483 | t0 = 0; |
1484 | // rt = t0 | |
1485 | ||
1486 | return t0; | |
f1aa6320 TS |
1487 | } |
1488 | ||
be24bb4f | 1489 | target_ulong do_evpe(target_ulong t0) |
f1aa6320 TS |
1490 | { |
1491 | // TODO | |
be24bb4f TS |
1492 | t0 = 0; |
1493 | // rt = t0 | |
1494 | ||
1495 | return t0; | |
f1aa6320 TS |
1496 | } |
1497 | ||
6c5c1e20 | 1498 | void do_fork(target_ulong t0, target_ulong t1) |
f1aa6320 | 1499 | { |
be24bb4f TS |
1500 | // t0 = rt, t1 = rs |
1501 | t0 = 0; | |
f1aa6320 TS |
1502 | // TODO: store to TC register |
1503 | } | |
1504 | ||
be24bb4f | 1505 | target_ulong do_yield(target_ulong t0) |
f1aa6320 | 1506 | { |
be24bb4f | 1507 | if (t0 < 0) { |
f1aa6320 | 1508 | /* No scheduling policy implemented. */ |
be24bb4f | 1509 | if (t0 != -2) { |
f1aa6320 | 1510 | if (env->CP0_VPEControl & (1 << CP0VPECo_YSI) && |
b5dc7732 | 1511 | env->active_tc.CP0_TCStatus & (1 << CP0TCSt_DT)) { |
f1aa6320 TS |
1512 | env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT); |
1513 | env->CP0_VPEControl |= 4 << CP0VPECo_EXCPT; | |
1514 | do_raise_exception(EXCP_THREAD); | |
1515 | } | |
1516 | } | |
be24bb4f | 1517 | } else if (t0 == 0) { |
f1aa6320 TS |
1518 | if (0 /* TODO: TC underflow */) { |
1519 | env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT); | |
1520 | do_raise_exception(EXCP_THREAD); | |
1521 | } else { | |
1522 | // TODO: Deallocate TC | |
1523 | } | |
be24bb4f | 1524 | } else if (t0 > 0) { |
f1aa6320 TS |
1525 | /* Yield qualifier inputs not implemented. */ |
1526 | env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT); | |
1527 | env->CP0_VPEControl |= 2 << CP0VPECo_EXCPT; | |
1528 | do_raise_exception(EXCP_THREAD); | |
1529 | } | |
be24bb4f | 1530 | return env->CP0_YQMask; |
f1aa6320 TS |
1531 | } |
1532 | ||
f1aa6320 | 1533 | #ifndef CONFIG_USER_ONLY |
6af0bf9c | 1534 | /* TLB management */ |
814b9a47 TS |
1535 | void cpu_mips_tlb_flush (CPUState *env, int flush_global) |
1536 | { | |
1537 | /* Flush qemu's TLB and discard all shadowed entries. */ | |
1538 | tlb_flush (env, flush_global); | |
ead9360e | 1539 | env->tlb->tlb_in_use = env->tlb->nb_tlb; |
814b9a47 TS |
1540 | } |
1541 | ||
29929e34 | 1542 | static void r4k_mips_tlb_flush_extra (CPUState *env, int first) |
814b9a47 TS |
1543 | { |
1544 | /* Discard entries from env->tlb[first] onwards. */ | |
ead9360e TS |
1545 | while (env->tlb->tlb_in_use > first) { |
1546 | r4k_invalidate_tlb(env, --env->tlb->tlb_in_use, 0); | |
814b9a47 TS |
1547 | } |
1548 | } | |
1549 | ||
29929e34 | 1550 | static void r4k_fill_tlb (int idx) |
6af0bf9c | 1551 | { |
29929e34 | 1552 | r4k_tlb_t *tlb; |
6af0bf9c FB |
1553 | |
1554 | /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */ | |
ead9360e | 1555 | tlb = &env->tlb->mmu.r4k.tlb[idx]; |
f2e9ebef | 1556 | tlb->VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1); |
d26bc211 | 1557 | #if defined(TARGET_MIPS64) |
e034e2c3 | 1558 | tlb->VPN &= env->SEGMask; |
100ce988 | 1559 | #endif |
98c1b82b | 1560 | tlb->ASID = env->CP0_EntryHi & 0xFF; |
3b1c8be4 | 1561 | tlb->PageMask = env->CP0_PageMask; |
6af0bf9c | 1562 | tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1; |
98c1b82b PB |
1563 | tlb->V0 = (env->CP0_EntryLo0 & 2) != 0; |
1564 | tlb->D0 = (env->CP0_EntryLo0 & 4) != 0; | |
1565 | tlb->C0 = (env->CP0_EntryLo0 >> 3) & 0x7; | |
6af0bf9c | 1566 | tlb->PFN[0] = (env->CP0_EntryLo0 >> 6) << 12; |
98c1b82b PB |
1567 | tlb->V1 = (env->CP0_EntryLo1 & 2) != 0; |
1568 | tlb->D1 = (env->CP0_EntryLo1 & 4) != 0; | |
1569 | tlb->C1 = (env->CP0_EntryLo1 >> 3) & 0x7; | |
6af0bf9c FB |
1570 | tlb->PFN[1] = (env->CP0_EntryLo1 >> 6) << 12; |
1571 | } | |
1572 | ||
29929e34 | 1573 | void r4k_do_tlbwi (void) |
6af0bf9c | 1574 | { |
bbc0d79c AJ |
1575 | int idx; |
1576 | ||
1577 | idx = (env->CP0_Index & ~0x80000000) % env->tlb->nb_tlb; | |
1578 | ||
814b9a47 TS |
1579 | /* Discard cached TLB entries. We could avoid doing this if the |
1580 | tlbwi is just upgrading access permissions on the current entry; | |
1581 | that might be a further win. */ | |
ead9360e | 1582 | r4k_mips_tlb_flush_extra (env, env->tlb->nb_tlb); |
814b9a47 | 1583 | |
bbc0d79c AJ |
1584 | r4k_invalidate_tlb(env, idx, 0); |
1585 | r4k_fill_tlb(idx); | |
6af0bf9c FB |
1586 | } |
1587 | ||
29929e34 | 1588 | void r4k_do_tlbwr (void) |
6af0bf9c FB |
1589 | { |
1590 | int r = cpu_mips_get_random(env); | |
1591 | ||
29929e34 TS |
1592 | r4k_invalidate_tlb(env, r, 1); |
1593 | r4k_fill_tlb(r); | |
6af0bf9c FB |
1594 | } |
1595 | ||
29929e34 | 1596 | void r4k_do_tlbp (void) |
6af0bf9c | 1597 | { |
29929e34 | 1598 | r4k_tlb_t *tlb; |
f2e9ebef | 1599 | target_ulong mask; |
6af0bf9c | 1600 | target_ulong tag; |
f2e9ebef | 1601 | target_ulong VPN; |
6af0bf9c FB |
1602 | uint8_t ASID; |
1603 | int i; | |
1604 | ||
3d9fb9fe | 1605 | ASID = env->CP0_EntryHi & 0xFF; |
ead9360e TS |
1606 | for (i = 0; i < env->tlb->nb_tlb; i++) { |
1607 | tlb = &env->tlb->mmu.r4k.tlb[i]; | |
f2e9ebef TS |
1608 | /* 1k pages are not supported. */ |
1609 | mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1); | |
1610 | tag = env->CP0_EntryHi & ~mask; | |
1611 | VPN = tlb->VPN & ~mask; | |
6af0bf9c | 1612 | /* Check ASID, virtual page number & size */ |
f2e9ebef | 1613 | if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) { |
6af0bf9c | 1614 | /* TLB match */ |
9c2149c8 | 1615 | env->CP0_Index = i; |
6af0bf9c FB |
1616 | break; |
1617 | } | |
1618 | } | |
ead9360e | 1619 | if (i == env->tlb->nb_tlb) { |
814b9a47 | 1620 | /* No match. Discard any shadow entries, if any of them match. */ |
ead9360e TS |
1621 | for (i = env->tlb->nb_tlb; i < env->tlb->tlb_in_use; i++) { |
1622 | tlb = &env->tlb->mmu.r4k.tlb[i]; | |
f2e9ebef TS |
1623 | /* 1k pages are not supported. */ |
1624 | mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1); | |
1625 | tag = env->CP0_EntryHi & ~mask; | |
1626 | VPN = tlb->VPN & ~mask; | |
814b9a47 | 1627 | /* Check ASID, virtual page number & size */ |
f2e9ebef | 1628 | if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) { |
29929e34 | 1629 | r4k_mips_tlb_flush_extra (env, i); |
814b9a47 TS |
1630 | break; |
1631 | } | |
1632 | } | |
1633 | ||
9c2149c8 | 1634 | env->CP0_Index |= 0x80000000; |
6af0bf9c FB |
1635 | } |
1636 | } | |
1637 | ||
29929e34 | 1638 | void r4k_do_tlbr (void) |
6af0bf9c | 1639 | { |
29929e34 | 1640 | r4k_tlb_t *tlb; |
09c56b84 | 1641 | uint8_t ASID; |
bbc0d79c | 1642 | int idx; |
6af0bf9c | 1643 | |
09c56b84 | 1644 | ASID = env->CP0_EntryHi & 0xFF; |
bbc0d79c AJ |
1645 | idx = (env->CP0_Index & ~0x80000000) % env->tlb->nb_tlb; |
1646 | tlb = &env->tlb->mmu.r4k.tlb[idx]; | |
4ad40f36 FB |
1647 | |
1648 | /* If this will change the current ASID, flush qemu's TLB. */ | |
814b9a47 TS |
1649 | if (ASID != tlb->ASID) |
1650 | cpu_mips_tlb_flush (env, 1); | |
1651 | ||
ead9360e | 1652 | r4k_mips_tlb_flush_extra(env, env->tlb->nb_tlb); |
4ad40f36 | 1653 | |
6af0bf9c | 1654 | env->CP0_EntryHi = tlb->VPN | tlb->ASID; |
3b1c8be4 | 1655 | env->CP0_PageMask = tlb->PageMask; |
7495fd0f TS |
1656 | env->CP0_EntryLo0 = tlb->G | (tlb->V0 << 1) | (tlb->D0 << 2) | |
1657 | (tlb->C0 << 3) | (tlb->PFN[0] >> 6); | |
1658 | env->CP0_EntryLo1 = tlb->G | (tlb->V1 << 1) | (tlb->D1 << 2) | | |
1659 | (tlb->C1 << 3) | (tlb->PFN[1] >> 6); | |
6af0bf9c | 1660 | } |
6af0bf9c | 1661 | |
2b0233ab | 1662 | /* Specials */ |
2796188e | 1663 | target_ulong do_di (void) |
2b0233ab | 1664 | { |
2796188e TS |
1665 | target_ulong t0 = env->CP0_Status; |
1666 | ||
be24bb4f | 1667 | env->CP0_Status = t0 & ~(1 << CP0St_IE); |
2b0233ab | 1668 | cpu_mips_update_irq(env); |
be24bb4f TS |
1669 | |
1670 | return t0; | |
2b0233ab TS |
1671 | } |
1672 | ||
2796188e | 1673 | target_ulong do_ei (void) |
2b0233ab | 1674 | { |
2796188e TS |
1675 | target_ulong t0 = env->CP0_Status; |
1676 | ||
be24bb4f | 1677 | env->CP0_Status = t0 | (1 << CP0St_IE); |
2b0233ab | 1678 | cpu_mips_update_irq(env); |
be24bb4f TS |
1679 | |
1680 | return t0; | |
2b0233ab TS |
1681 | } |
1682 | ||
f41c52f1 | 1683 | void debug_pre_eret (void) |
6af0bf9c | 1684 | { |
f41c52f1 | 1685 | fprintf(logfile, "ERET: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx, |
b5dc7732 | 1686 | env->active_tc.PC, env->CP0_EPC); |
f41c52f1 TS |
1687 | if (env->CP0_Status & (1 << CP0St_ERL)) |
1688 | fprintf(logfile, " ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC); | |
1689 | if (env->hflags & MIPS_HFLAG_DM) | |
1690 | fprintf(logfile, " DEPC " TARGET_FMT_lx, env->CP0_DEPC); | |
1691 | fputs("\n", logfile); | |
1692 | } | |
1693 | ||
1694 | void debug_post_eret (void) | |
1695 | { | |
744e0915 | 1696 | fprintf(logfile, " => PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx, |
b5dc7732 | 1697 | env->active_tc.PC, env->CP0_EPC); |
f41c52f1 TS |
1698 | if (env->CP0_Status & (1 << CP0St_ERL)) |
1699 | fprintf(logfile, " ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC); | |
1700 | if (env->hflags & MIPS_HFLAG_DM) | |
1701 | fprintf(logfile, " DEPC " TARGET_FMT_lx, env->CP0_DEPC); | |
623a930e TS |
1702 | switch (env->hflags & MIPS_HFLAG_KSU) { |
1703 | case MIPS_HFLAG_UM: fputs(", UM\n", logfile); break; | |
1704 | case MIPS_HFLAG_SM: fputs(", SM\n", logfile); break; | |
1705 | case MIPS_HFLAG_KM: fputs("\n", logfile); break; | |
1706 | default: cpu_abort(env, "Invalid MMU mode!\n"); break; | |
1707 | } | |
6af0bf9c FB |
1708 | } |
1709 | ||
6c5c1e20 | 1710 | void do_eret (void) |
2b0233ab TS |
1711 | { |
1712 | if (loglevel & CPU_LOG_EXEC) | |
1713 | debug_pre_eret(); | |
1714 | if (env->CP0_Status & (1 << CP0St_ERL)) { | |
b5dc7732 | 1715 | env->active_tc.PC = env->CP0_ErrorEPC; |
2b0233ab TS |
1716 | env->CP0_Status &= ~(1 << CP0St_ERL); |
1717 | } else { | |
b5dc7732 | 1718 | env->active_tc.PC = env->CP0_EPC; |
2b0233ab TS |
1719 | env->CP0_Status &= ~(1 << CP0St_EXL); |
1720 | } | |
1721 | compute_hflags(env); | |
1722 | if (loglevel & CPU_LOG_EXEC) | |
1723 | debug_post_eret(); | |
1724 | env->CP0_LLAddr = 1; | |
1725 | } | |
1726 | ||
6c5c1e20 | 1727 | void do_deret (void) |
2b0233ab TS |
1728 | { |
1729 | if (loglevel & CPU_LOG_EXEC) | |
1730 | debug_pre_eret(); | |
b5dc7732 | 1731 | env->active_tc.PC = env->CP0_DEPC; |
2b0233ab TS |
1732 | env->hflags &= MIPS_HFLAG_DM; |
1733 | compute_hflags(env); | |
1734 | if (loglevel & CPU_LOG_EXEC) | |
1735 | debug_post_eret(); | |
1736 | env->CP0_LLAddr = 1; | |
1737 | } | |
0eaef5aa | 1738 | #endif /* !CONFIG_USER_ONLY */ |
2b0233ab | 1739 | |
2796188e | 1740 | target_ulong do_rdhwr_cpunum(void) |
2b0233ab TS |
1741 | { |
1742 | if ((env->hflags & MIPS_HFLAG_CP0) || | |
1743 | (env->CP0_HWREna & (1 << 0))) | |
2796188e | 1744 | return env->CP0_EBase & 0x3ff; |
2b0233ab TS |
1745 | else |
1746 | do_raise_exception(EXCP_RI); | |
be24bb4f | 1747 | |
2796188e | 1748 | return 0; |
2b0233ab TS |
1749 | } |
1750 | ||
2796188e | 1751 | target_ulong do_rdhwr_synci_step(void) |
2b0233ab TS |
1752 | { |
1753 | if ((env->hflags & MIPS_HFLAG_CP0) || | |
1754 | (env->CP0_HWREna & (1 << 1))) | |
2796188e | 1755 | return env->SYNCI_Step; |
2b0233ab TS |
1756 | else |
1757 | do_raise_exception(EXCP_RI); | |
be24bb4f | 1758 | |
2796188e | 1759 | return 0; |
2b0233ab TS |
1760 | } |
1761 | ||
2796188e | 1762 | target_ulong do_rdhwr_cc(void) |
2b0233ab TS |
1763 | { |
1764 | if ((env->hflags & MIPS_HFLAG_CP0) || | |
1765 | (env->CP0_HWREna & (1 << 2))) | |
2796188e | 1766 | return env->CP0_Count; |
2b0233ab TS |
1767 | else |
1768 | do_raise_exception(EXCP_RI); | |
be24bb4f | 1769 | |
2796188e | 1770 | return 0; |
2b0233ab TS |
1771 | } |
1772 | ||
2796188e | 1773 | target_ulong do_rdhwr_ccres(void) |
2b0233ab TS |
1774 | { |
1775 | if ((env->hflags & MIPS_HFLAG_CP0) || | |
1776 | (env->CP0_HWREna & (1 << 3))) | |
2796188e | 1777 | return env->CCRes; |
2b0233ab TS |
1778 | else |
1779 | do_raise_exception(EXCP_RI); | |
be24bb4f | 1780 | |
2796188e | 1781 | return 0; |
2b0233ab TS |
1782 | } |
1783 | ||
1784 | /* Bitfield operations. */ | |
d26968ec | 1785 | target_ulong do_ext(target_ulong t1, uint32_t pos, uint32_t size) |
2b0233ab | 1786 | { |
be24bb4f | 1787 | return (int32_t)((t1 >> pos) & ((size < 32) ? ((1 << size) - 1) : ~0)); |
2b0233ab TS |
1788 | } |
1789 | ||
be24bb4f | 1790 | target_ulong do_ins(target_ulong t0, target_ulong t1, uint32_t pos, uint32_t size) |
2b0233ab TS |
1791 | { |
1792 | target_ulong mask = ((size < 32) ? ((1 << size) - 1) : ~0) << pos; | |
1793 | ||
be24bb4f | 1794 | return (int32_t)((t0 & ~mask) | ((t1 << pos) & mask)); |
2b0233ab TS |
1795 | } |
1796 | ||
d26968ec | 1797 | target_ulong do_wsbh(target_ulong t1) |
2b0233ab | 1798 | { |
be24bb4f | 1799 | return (int32_t)(((t1 << 8) & ~0x00FF00FF) | ((t1 >> 8) & 0x00FF00FF)); |
2b0233ab TS |
1800 | } |
1801 | ||
1802 | #if defined(TARGET_MIPS64) | |
d26968ec | 1803 | target_ulong do_dext(target_ulong t1, uint32_t pos, uint32_t size) |
2b0233ab | 1804 | { |
be24bb4f | 1805 | return (t1 >> pos) & ((size < 64) ? ((1ULL << size) - 1) : ~0ULL); |
2b0233ab TS |
1806 | } |
1807 | ||
be24bb4f | 1808 | target_ulong do_dins(target_ulong t0, target_ulong t1, uint32_t pos, uint32_t size) |
2b0233ab TS |
1809 | { |
1810 | target_ulong mask = ((size < 64) ? ((1ULL << size) - 1) : ~0ULL) << pos; | |
1811 | ||
be24bb4f | 1812 | return (t0 & ~mask) | ((t1 << pos) & mask); |
2b0233ab TS |
1813 | } |
1814 | ||
d26968ec | 1815 | target_ulong do_dsbh(target_ulong t1) |
2b0233ab | 1816 | { |
be24bb4f | 1817 | return ((t1 << 8) & ~0x00FF00FF00FF00FFULL) | ((t1 >> 8) & 0x00FF00FF00FF00FFULL); |
2b0233ab TS |
1818 | } |
1819 | ||
d26968ec | 1820 | target_ulong do_dshd(target_ulong t1) |
2b0233ab | 1821 | { |
be24bb4f TS |
1822 | t1 = ((t1 << 16) & ~0x0000FFFF0000FFFFULL) | ((t1 >> 16) & 0x0000FFFF0000FFFFULL); |
1823 | return (t1 << 32) | (t1 >> 32); | |
2b0233ab TS |
1824 | } |
1825 | #endif | |
1826 | ||
6af0bf9c FB |
1827 | void do_pmon (int function) |
1828 | { | |
1829 | function /= 2; | |
1830 | switch (function) { | |
1831 | case 2: /* TODO: char inbyte(int waitflag); */ | |
b5dc7732 TS |
1832 | if (env->active_tc.gpr[4] == 0) |
1833 | env->active_tc.gpr[2] = -1; | |
6af0bf9c FB |
1834 | /* Fall through */ |
1835 | case 11: /* TODO: char inbyte (void); */ | |
b5dc7732 | 1836 | env->active_tc.gpr[2] = -1; |
6af0bf9c FB |
1837 | break; |
1838 | case 3: | |
1839 | case 12: | |
b5dc7732 | 1840 | printf("%c", (char)(env->active_tc.gpr[4] & 0xFF)); |
6af0bf9c FB |
1841 | break; |
1842 | case 17: | |
1843 | break; | |
1844 | case 158: | |
1845 | { | |
b5dc7732 | 1846 | unsigned char *fmt = (void *)(unsigned long)env->active_tc.gpr[4]; |
6af0bf9c FB |
1847 | printf("%s", fmt); |
1848 | } | |
1849 | break; | |
1850 | } | |
1851 | } | |
e37e863f | 1852 | |
08ba7963 TS |
1853 | void do_wait (void) |
1854 | { | |
1855 | env->halted = 1; | |
1856 | do_raise_exception(EXCP_HLT); | |
1857 | } | |
1858 | ||
5fafdf24 | 1859 | #if !defined(CONFIG_USER_ONLY) |
e37e863f | 1860 | |
4ad40f36 FB |
1861 | static void do_unaligned_access (target_ulong addr, int is_write, int is_user, void *retaddr); |
1862 | ||
e37e863f | 1863 | #define MMUSUFFIX _mmu |
4ad40f36 | 1864 | #define ALIGNED_ONLY |
e37e863f FB |
1865 | |
1866 | #define SHIFT 0 | |
1867 | #include "softmmu_template.h" | |
1868 | ||
1869 | #define SHIFT 1 | |
1870 | #include "softmmu_template.h" | |
1871 | ||
1872 | #define SHIFT 2 | |
1873 | #include "softmmu_template.h" | |
1874 | ||
1875 | #define SHIFT 3 | |
1876 | #include "softmmu_template.h" | |
1877 | ||
4ad40f36 FB |
1878 | static void do_unaligned_access (target_ulong addr, int is_write, int is_user, void *retaddr) |
1879 | { | |
1880 | env->CP0_BadVAddr = addr; | |
1881 | do_restore_state (retaddr); | |
1882 | do_raise_exception ((is_write == 1) ? EXCP_AdES : EXCP_AdEL); | |
1883 | } | |
1884 | ||
6ebbf390 | 1885 | void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) |
e37e863f FB |
1886 | { |
1887 | TranslationBlock *tb; | |
1888 | CPUState *saved_env; | |
1889 | unsigned long pc; | |
1890 | int ret; | |
1891 | ||
1892 | /* XXX: hack to restore env in all cases, even if not called from | |
1893 | generated code */ | |
1894 | saved_env = env; | |
1895 | env = cpu_single_env; | |
6ebbf390 | 1896 | ret = cpu_mips_handle_mmu_fault(env, addr, is_write, mmu_idx, 1); |
e37e863f FB |
1897 | if (ret) { |
1898 | if (retaddr) { | |
1899 | /* now we have a real cpu fault */ | |
1900 | pc = (unsigned long)retaddr; | |
1901 | tb = tb_find_pc(pc); | |
1902 | if (tb) { | |
1903 | /* the PC is inside the translated code. It means that we have | |
1904 | a virtual CPU fault */ | |
1905 | cpu_restore_state(tb, env, pc, NULL); | |
1906 | } | |
1907 | } | |
1908 | do_raise_exception_err(env->exception_index, env->error_code); | |
1909 | } | |
1910 | env = saved_env; | |
1911 | } | |
1912 | ||
647de6ca TS |
1913 | void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec, |
1914 | int unused) | |
1915 | { | |
1916 | if (is_exec) | |
1917 | do_raise_exception(EXCP_IBE); | |
1918 | else | |
1919 | do_raise_exception(EXCP_DBE); | |
1920 | } | |
f1aa6320 | 1921 | #endif /* !CONFIG_USER_ONLY */ |
fd4a04eb TS |
1922 | |
1923 | /* Complex FPU operations which may need stack space. */ | |
1924 | ||
f090c9d4 PB |
1925 | #define FLOAT_ONE32 make_float32(0x3f8 << 20) |
1926 | #define FLOAT_ONE64 make_float64(0x3ffULL << 52) | |
1927 | #define FLOAT_TWO32 make_float32(1 << 30) | |
1928 | #define FLOAT_TWO64 make_float64(1ULL << 62) | |
54454097 TS |
1929 | #define FLOAT_QNAN32 0x7fbfffff |
1930 | #define FLOAT_QNAN64 0x7ff7ffffffffffffULL | |
1931 | #define FLOAT_SNAN32 0x7fffffff | |
1932 | #define FLOAT_SNAN64 0x7fffffffffffffffULL | |
8dfdb87c | 1933 | |
fd4a04eb TS |
1934 | /* convert MIPS rounding mode in FCR31 to IEEE library */ |
1935 | unsigned int ieee_rm[] = { | |
1936 | float_round_nearest_even, | |
1937 | float_round_to_zero, | |
1938 | float_round_up, | |
1939 | float_round_down | |
1940 | }; | |
1941 | ||
1942 | #define RESTORE_ROUNDING_MODE \ | |
ead9360e | 1943 | set_float_rounding_mode(ieee_rm[env->fpu->fcr31 & 3], &env->fpu->fp_status) |
fd4a04eb | 1944 | |
6c5c1e20 | 1945 | target_ulong do_cfc1 (uint32_t reg) |
fd4a04eb | 1946 | { |
6c5c1e20 TS |
1947 | target_ulong t0; |
1948 | ||
ead9360e TS |
1949 | switch (reg) { |
1950 | case 0: | |
be24bb4f | 1951 | t0 = (int32_t)env->fpu->fcr0; |
ead9360e TS |
1952 | break; |
1953 | case 25: | |
be24bb4f | 1954 | t0 = ((env->fpu->fcr31 >> 24) & 0xfe) | ((env->fpu->fcr31 >> 23) & 0x1); |
ead9360e TS |
1955 | break; |
1956 | case 26: | |
be24bb4f | 1957 | t0 = env->fpu->fcr31 & 0x0003f07c; |
ead9360e TS |
1958 | break; |
1959 | case 28: | |
be24bb4f | 1960 | t0 = (env->fpu->fcr31 & 0x00000f83) | ((env->fpu->fcr31 >> 22) & 0x4); |
ead9360e TS |
1961 | break; |
1962 | default: | |
be24bb4f | 1963 | t0 = (int32_t)env->fpu->fcr31; |
ead9360e TS |
1964 | break; |
1965 | } | |
be24bb4f TS |
1966 | |
1967 | return t0; | |
ead9360e TS |
1968 | } |
1969 | ||
be24bb4f | 1970 | void do_ctc1 (target_ulong t0, uint32_t reg) |
ead9360e TS |
1971 | { |
1972 | switch(reg) { | |
fd4a04eb | 1973 | case 25: |
be24bb4f | 1974 | if (t0 & 0xffffff00) |
fd4a04eb | 1975 | return; |
be24bb4f TS |
1976 | env->fpu->fcr31 = (env->fpu->fcr31 & 0x017fffff) | ((t0 & 0xfe) << 24) | |
1977 | ((t0 & 0x1) << 23); | |
fd4a04eb TS |
1978 | break; |
1979 | case 26: | |
be24bb4f | 1980 | if (t0 & 0x007c0000) |
fd4a04eb | 1981 | return; |
be24bb4f | 1982 | env->fpu->fcr31 = (env->fpu->fcr31 & 0xfffc0f83) | (t0 & 0x0003f07c); |
fd4a04eb TS |
1983 | break; |
1984 | case 28: | |
be24bb4f | 1985 | if (t0 & 0x007c0000) |
fd4a04eb | 1986 | return; |
be24bb4f TS |
1987 | env->fpu->fcr31 = (env->fpu->fcr31 & 0xfefff07c) | (t0 & 0x00000f83) | |
1988 | ((t0 & 0x4) << 22); | |
fd4a04eb TS |
1989 | break; |
1990 | case 31: | |
be24bb4f | 1991 | if (t0 & 0x007c0000) |
fd4a04eb | 1992 | return; |
be24bb4f | 1993 | env->fpu->fcr31 = t0; |
fd4a04eb TS |
1994 | break; |
1995 | default: | |
1996 | return; | |
1997 | } | |
1998 | /* set rounding mode */ | |
1999 | RESTORE_ROUNDING_MODE; | |
ead9360e TS |
2000 | set_float_exception_flags(0, &env->fpu->fp_status); |
2001 | if ((GET_FP_ENABLE(env->fpu->fcr31) | 0x20) & GET_FP_CAUSE(env->fpu->fcr31)) | |
fd4a04eb TS |
2002 | do_raise_exception(EXCP_FPE); |
2003 | } | |
2004 | ||
c904ef0e | 2005 | static inline char ieee_ex_to_mips(char xcpt) |
fd4a04eb TS |
2006 | { |
2007 | return (xcpt & float_flag_inexact) >> 5 | | |
2008 | (xcpt & float_flag_underflow) >> 3 | | |
2009 | (xcpt & float_flag_overflow) >> 1 | | |
2010 | (xcpt & float_flag_divbyzero) << 1 | | |
2011 | (xcpt & float_flag_invalid) << 4; | |
2012 | } | |
2013 | ||
c904ef0e | 2014 | static inline char mips_ex_to_ieee(char xcpt) |
fd4a04eb TS |
2015 | { |
2016 | return (xcpt & FP_INEXACT) << 5 | | |
2017 | (xcpt & FP_UNDERFLOW) << 3 | | |
2018 | (xcpt & FP_OVERFLOW) << 1 | | |
2019 | (xcpt & FP_DIV0) >> 1 | | |
2020 | (xcpt & FP_INVALID) >> 4; | |
2021 | } | |
2022 | ||
c904ef0e | 2023 | static inline void update_fcr31(void) |
fd4a04eb | 2024 | { |
ead9360e | 2025 | int tmp = ieee_ex_to_mips(get_float_exception_flags(&env->fpu->fp_status)); |
fd4a04eb | 2026 | |
ead9360e TS |
2027 | SET_FP_CAUSE(env->fpu->fcr31, tmp); |
2028 | if (GET_FP_ENABLE(env->fpu->fcr31) & tmp) | |
fd4a04eb TS |
2029 | do_raise_exception(EXCP_FPE); |
2030 | else | |
ead9360e | 2031 | UPDATE_FP_FLAGS(env->fpu->fcr31, tmp); |
fd4a04eb TS |
2032 | } |
2033 | ||
a16336e4 TS |
2034 | /* Float support. |
2035 | Single precition routines have a "s" suffix, double precision a | |
2036 | "d" suffix, 32bit integer "w", 64bit integer "l", paired single "ps", | |
2037 | paired single lower "pl", paired single upper "pu". */ | |
2038 | ||
a16336e4 | 2039 | /* unary operations, modifying fp status */ |
b6d96bed TS |
2040 | uint64_t do_float_sqrt_d(uint64_t fdt0) |
2041 | { | |
2042 | return float64_sqrt(fdt0, &env->fpu->fp_status); | |
2043 | } | |
2044 | ||
2045 | uint32_t do_float_sqrt_s(uint32_t fst0) | |
2046 | { | |
2047 | return float32_sqrt(fst0, &env->fpu->fp_status); | |
2048 | } | |
a16336e4 | 2049 | |
b6d96bed | 2050 | uint64_t do_float_cvtd_s(uint32_t fst0) |
fd4a04eb | 2051 | { |
b6d96bed TS |
2052 | uint64_t fdt2; |
2053 | ||
ead9360e | 2054 | set_float_exception_flags(0, &env->fpu->fp_status); |
b6d96bed | 2055 | fdt2 = float32_to_float64(fst0, &env->fpu->fp_status); |
fd4a04eb | 2056 | update_fcr31(); |
b6d96bed | 2057 | return fdt2; |
fd4a04eb | 2058 | } |
b6d96bed TS |
2059 | |
2060 | uint64_t do_float_cvtd_w(uint32_t wt0) | |
fd4a04eb | 2061 | { |
b6d96bed TS |
2062 | uint64_t fdt2; |
2063 | ||
ead9360e | 2064 | set_float_exception_flags(0, &env->fpu->fp_status); |
b6d96bed | 2065 | fdt2 = int32_to_float64(wt0, &env->fpu->fp_status); |
fd4a04eb | 2066 | update_fcr31(); |
b6d96bed | 2067 | return fdt2; |
fd4a04eb | 2068 | } |
b6d96bed TS |
2069 | |
2070 | uint64_t do_float_cvtd_l(uint64_t dt0) | |
fd4a04eb | 2071 | { |
b6d96bed TS |
2072 | uint64_t fdt2; |
2073 | ||
ead9360e | 2074 | set_float_exception_flags(0, &env->fpu->fp_status); |
b6d96bed | 2075 | fdt2 = int64_to_float64(dt0, &env->fpu->fp_status); |
fd4a04eb | 2076 | update_fcr31(); |
b6d96bed | 2077 | return fdt2; |
fd4a04eb | 2078 | } |
b6d96bed TS |
2079 | |
2080 | uint64_t do_float_cvtl_d(uint64_t fdt0) | |
fd4a04eb | 2081 | { |
b6d96bed TS |
2082 | uint64_t dt2; |
2083 | ||
ead9360e | 2084 | set_float_exception_flags(0, &env->fpu->fp_status); |
b6d96bed | 2085 | dt2 = float64_to_int64(fdt0, &env->fpu->fp_status); |
fd4a04eb | 2086 | update_fcr31(); |
ead9360e | 2087 | if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) |
b6d96bed TS |
2088 | dt2 = FLOAT_SNAN64; |
2089 | return dt2; | |
fd4a04eb | 2090 | } |
b6d96bed TS |
2091 | |
2092 | uint64_t do_float_cvtl_s(uint32_t fst0) | |
fd4a04eb | 2093 | { |
b6d96bed TS |
2094 | uint64_t dt2; |
2095 | ||
ead9360e | 2096 | set_float_exception_flags(0, &env->fpu->fp_status); |
b6d96bed | 2097 | dt2 = float32_to_int64(fst0, &env->fpu->fp_status); |
fd4a04eb | 2098 | update_fcr31(); |
ead9360e | 2099 | if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) |
b6d96bed TS |
2100 | dt2 = FLOAT_SNAN64; |
2101 | return dt2; | |
fd4a04eb TS |
2102 | } |
2103 | ||
b6d96bed | 2104 | uint64_t do_float_cvtps_pw(uint64_t dt0) |
fd4a04eb | 2105 | { |
b6d96bed TS |
2106 | uint32_t fst2; |
2107 | uint32_t fsth2; | |
2108 | ||
ead9360e | 2109 | set_float_exception_flags(0, &env->fpu->fp_status); |
b6d96bed TS |
2110 | fst2 = int32_to_float32(dt0 & 0XFFFFFFFF, &env->fpu->fp_status); |
2111 | fsth2 = int32_to_float32(dt0 >> 32, &env->fpu->fp_status); | |
fd4a04eb | 2112 | update_fcr31(); |
b6d96bed | 2113 | return ((uint64_t)fsth2 << 32) | fst2; |
fd4a04eb | 2114 | } |
b6d96bed TS |
2115 | |
2116 | uint64_t do_float_cvtpw_ps(uint64_t fdt0) | |
fd4a04eb | 2117 | { |
b6d96bed TS |
2118 | uint32_t wt2; |
2119 | uint32_t wth2; | |
2120 | ||
ead9360e | 2121 | set_float_exception_flags(0, &env->fpu->fp_status); |
b6d96bed TS |
2122 | wt2 = float32_to_int32(fdt0 & 0XFFFFFFFF, &env->fpu->fp_status); |
2123 | wth2 = float32_to_int32(fdt0 >> 32, &env->fpu->fp_status); | |
fd4a04eb | 2124 | update_fcr31(); |
b6d96bed TS |
2125 | if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) { |
2126 | wt2 = FLOAT_SNAN32; | |
2127 | wth2 = FLOAT_SNAN32; | |
2128 | } | |
2129 | return ((uint64_t)wth2 << 32) | wt2; | |
fd4a04eb | 2130 | } |
b6d96bed TS |
2131 | |
2132 | uint32_t do_float_cvts_d(uint64_t fdt0) | |
fd4a04eb | 2133 | { |
b6d96bed TS |
2134 | uint32_t fst2; |
2135 | ||
ead9360e | 2136 | set_float_exception_flags(0, &env->fpu->fp_status); |
b6d96bed | 2137 | fst2 = float64_to_float32(fdt0, &env->fpu->fp_status); |
fd4a04eb | 2138 | update_fcr31(); |
b6d96bed | 2139 | return fst2; |
fd4a04eb | 2140 | } |
b6d96bed TS |
2141 | |
2142 | uint32_t do_float_cvts_w(uint32_t wt0) | |
fd4a04eb | 2143 | { |
b6d96bed TS |
2144 | uint32_t fst2; |
2145 | ||
ead9360e | 2146 | set_float_exception_flags(0, &env->fpu->fp_status); |
b6d96bed | 2147 | fst2 = int32_to_float32(wt0, &env->fpu->fp_status); |
fd4a04eb | 2148 | update_fcr31(); |
b6d96bed | 2149 | return fst2; |
fd4a04eb | 2150 | } |
b6d96bed TS |
2151 | |
2152 | uint32_t do_float_cvts_l(uint64_t dt0) | |
fd4a04eb | 2153 | { |
b6d96bed TS |
2154 | uint32_t fst2; |
2155 | ||
ead9360e | 2156 | set_float_exception_flags(0, &env->fpu->fp_status); |
b6d96bed | 2157 | fst2 = int64_to_float32(dt0, &env->fpu->fp_status); |
fd4a04eb | 2158 | update_fcr31(); |
b6d96bed | 2159 | return fst2; |
fd4a04eb | 2160 | } |
b6d96bed TS |
2161 | |
2162 | uint32_t do_float_cvts_pl(uint32_t wt0) | |
fd4a04eb | 2163 | { |
b6d96bed TS |
2164 | uint32_t wt2; |
2165 | ||
ead9360e | 2166 | set_float_exception_flags(0, &env->fpu->fp_status); |
b6d96bed | 2167 | wt2 = wt0; |
fd4a04eb | 2168 | update_fcr31(); |
b6d96bed | 2169 | return wt2; |
fd4a04eb | 2170 | } |
b6d96bed TS |
2171 | |
2172 | uint32_t do_float_cvts_pu(uint32_t wth0) | |
fd4a04eb | 2173 | { |
b6d96bed TS |
2174 | uint32_t wt2; |
2175 | ||
ead9360e | 2176 | set_float_exception_flags(0, &env->fpu->fp_status); |
b6d96bed | 2177 | wt2 = wth0; |
fd4a04eb | 2178 | update_fcr31(); |
b6d96bed | 2179 | return wt2; |
fd4a04eb | 2180 | } |
b6d96bed TS |
2181 | |
2182 | uint32_t do_float_cvtw_s(uint32_t fst0) | |
fd4a04eb | 2183 | { |
b6d96bed TS |
2184 | uint32_t wt2; |
2185 | ||
ead9360e | 2186 | set_float_exception_flags(0, &env->fpu->fp_status); |
b6d96bed | 2187 | wt2 = float32_to_int32(fst0, &env->fpu->fp_status); |
fd4a04eb | 2188 | update_fcr31(); |
ead9360e | 2189 | if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) |
b6d96bed TS |
2190 | wt2 = FLOAT_SNAN32; |
2191 | return wt2; | |
fd4a04eb | 2192 | } |
b6d96bed TS |
2193 | |
2194 | uint32_t do_float_cvtw_d(uint64_t fdt0) | |
fd4a04eb | 2195 | { |
b6d96bed TS |
2196 | uint32_t wt2; |
2197 | ||
ead9360e | 2198 | set_float_exception_flags(0, &env->fpu->fp_status); |
b6d96bed | 2199 | wt2 = float64_to_int32(fdt0, &env->fpu->fp_status); |
fd4a04eb | 2200 | update_fcr31(); |
ead9360e | 2201 | if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) |
b6d96bed TS |
2202 | wt2 = FLOAT_SNAN32; |
2203 | return wt2; | |
fd4a04eb TS |
2204 | } |
2205 | ||
b6d96bed | 2206 | uint64_t do_float_roundl_d(uint64_t fdt0) |
fd4a04eb | 2207 | { |
b6d96bed TS |
2208 | uint64_t dt2; |
2209 | ||
ead9360e | 2210 | set_float_rounding_mode(float_round_nearest_even, &env->fpu->fp_status); |
b6d96bed | 2211 | dt2 = float64_to_int64(fdt0, &env->fpu->fp_status); |
fd4a04eb TS |
2212 | RESTORE_ROUNDING_MODE; |
2213 | update_fcr31(); | |
ead9360e | 2214 | if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) |
b6d96bed TS |
2215 | dt2 = FLOAT_SNAN64; |
2216 | return dt2; | |
fd4a04eb | 2217 | } |
b6d96bed TS |
2218 | |
2219 | uint64_t do_float_roundl_s(uint32_t fst0) | |
fd4a04eb | 2220 | { |
b6d96bed TS |
2221 | uint64_t dt2; |
2222 | ||
ead9360e | 2223 | set_float_rounding_mode(float_round_nearest_even, &env->fpu->fp_status); |
b6d96bed | 2224 | dt2 = float32_to_int64(fst0, &env->fpu->fp_status); |
fd4a04eb TS |
2225 | RESTORE_ROUNDING_MODE; |
2226 | update_fcr31(); | |
ead9360e | 2227 | if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) |
b6d96bed TS |
2228 | dt2 = FLOAT_SNAN64; |
2229 | return dt2; | |
fd4a04eb | 2230 | } |
b6d96bed TS |
2231 | |
2232 | uint32_t do_float_roundw_d(uint64_t fdt0) | |
fd4a04eb | 2233 | { |
b6d96bed TS |
2234 | uint32_t wt2; |
2235 | ||
ead9360e | 2236 | set_float_rounding_mode(float_round_nearest_even, &env->fpu->fp_status); |
b6d96bed | 2237 | wt2 = float64_to_int32(fdt0, &env->fpu->fp_status); |
fd4a04eb TS |
2238 | RESTORE_ROUNDING_MODE; |
2239 | update_fcr31(); | |
ead9360e | 2240 | if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) |
b6d96bed TS |
2241 | wt2 = FLOAT_SNAN32; |
2242 | return wt2; | |
fd4a04eb | 2243 | } |
b6d96bed TS |
2244 | |
2245 | uint32_t do_float_roundw_s(uint32_t fst0) | |
fd4a04eb | 2246 | { |
b6d96bed TS |
2247 | uint32_t wt2; |
2248 | ||
ead9360e | 2249 | set_float_rounding_mode(float_round_nearest_even, &env->fpu->fp_status); |
b6d96bed | 2250 | wt2 = float32_to_int32(fst0, &env->fpu->fp_status); |
fd4a04eb TS |
2251 | RESTORE_ROUNDING_MODE; |
2252 | update_fcr31(); | |
ead9360e | 2253 | if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) |
b6d96bed TS |
2254 | wt2 = FLOAT_SNAN32; |
2255 | return wt2; | |
fd4a04eb TS |
2256 | } |
2257 | ||
b6d96bed | 2258 | uint64_t do_float_truncl_d(uint64_t fdt0) |
fd4a04eb | 2259 | { |
b6d96bed TS |
2260 | uint64_t dt2; |
2261 | ||
2262 | dt2 = float64_to_int64_round_to_zero(fdt0, &env->fpu->fp_status); | |
fd4a04eb | 2263 | update_fcr31(); |
ead9360e | 2264 | if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) |
b6d96bed TS |
2265 | dt2 = FLOAT_SNAN64; |
2266 | return dt2; | |
fd4a04eb | 2267 | } |
b6d96bed TS |
2268 | |
2269 | uint64_t do_float_truncl_s(uint32_t fst0) | |
fd4a04eb | 2270 | { |
b6d96bed TS |
2271 | uint64_t dt2; |
2272 | ||
2273 | dt2 = float32_to_int64_round_to_zero(fst0, &env->fpu->fp_status); | |
fd4a04eb | 2274 | update_fcr31(); |
ead9360e | 2275 | if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) |
b6d96bed TS |
2276 | dt2 = FLOAT_SNAN64; |
2277 | return dt2; | |
fd4a04eb | 2278 | } |
b6d96bed TS |
2279 | |
2280 | uint32_t do_float_truncw_d(uint64_t fdt0) | |
fd4a04eb | 2281 | { |
b6d96bed TS |
2282 | uint32_t wt2; |
2283 | ||
2284 | wt2 = float64_to_int32_round_to_zero(fdt0, &env->fpu->fp_status); | |
fd4a04eb | 2285 | update_fcr31(); |
ead9360e | 2286 | if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) |
b6d96bed TS |
2287 | wt2 = FLOAT_SNAN32; |
2288 | return wt2; | |
fd4a04eb | 2289 | } |
b6d96bed TS |
2290 | |
2291 | uint32_t do_float_truncw_s(uint32_t fst0) | |
fd4a04eb | 2292 | { |
b6d96bed TS |
2293 | uint32_t wt2; |
2294 | ||
2295 | wt2 = float32_to_int32_round_to_zero(fst0, &env->fpu->fp_status); | |
fd4a04eb | 2296 | update_fcr31(); |
ead9360e | 2297 | if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) |
b6d96bed TS |
2298 | wt2 = FLOAT_SNAN32; |
2299 | return wt2; | |
fd4a04eb TS |
2300 | } |
2301 | ||
b6d96bed | 2302 | uint64_t do_float_ceill_d(uint64_t fdt0) |
fd4a04eb | 2303 | { |
b6d96bed TS |
2304 | uint64_t dt2; |
2305 | ||
ead9360e | 2306 | set_float_rounding_mode(float_round_up, &env->fpu->fp_status); |
b6d96bed | 2307 | dt2 = float64_to_int64(fdt0, &env->fpu->fp_status); |
fd4a04eb TS |
2308 | RESTORE_ROUNDING_MODE; |
2309 | update_fcr31(); | |
ead9360e | 2310 | if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) |
b6d96bed TS |
2311 | dt2 = FLOAT_SNAN64; |
2312 | return dt2; | |
fd4a04eb | 2313 | } |
b6d96bed TS |
2314 | |
2315 | uint64_t do_float_ceill_s(uint32_t fst0) | |
fd4a04eb | 2316 | { |
b6d96bed TS |
2317 | uint64_t dt2; |
2318 | ||
ead9360e | 2319 | set_float_rounding_mode(float_round_up, &env->fpu->fp_status); |
b6d96bed | 2320 | dt2 = float32_to_int64(fst0, &env->fpu->fp_status); |
fd4a04eb TS |
2321 | RESTORE_ROUNDING_MODE; |
2322 | update_fcr31(); | |
ead9360e | 2323 | if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) |
b6d96bed TS |
2324 | dt2 = FLOAT_SNAN64; |
2325 | return dt2; | |
fd4a04eb | 2326 | } |
b6d96bed TS |
2327 | |
2328 | uint32_t do_float_ceilw_d(uint64_t fdt0) | |
fd4a04eb | 2329 | { |
b6d96bed TS |
2330 | uint32_t wt2; |
2331 | ||
ead9360e | 2332 | set_float_rounding_mode(float_round_up, &env->fpu->fp_status); |
b6d96bed | 2333 | wt2 = float64_to_int32(fdt0, &env->fpu->fp_status); |
fd4a04eb TS |
2334 | RESTORE_ROUNDING_MODE; |
2335 | update_fcr31(); | |
ead9360e | 2336 | if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) |
b6d96bed TS |
2337 | wt2 = FLOAT_SNAN32; |
2338 | return wt2; | |
fd4a04eb | 2339 | } |
b6d96bed TS |
2340 | |
2341 | uint32_t do_float_ceilw_s(uint32_t fst0) | |
fd4a04eb | 2342 | { |
b6d96bed TS |
2343 | uint32_t wt2; |
2344 | ||
ead9360e | 2345 | set_float_rounding_mode(float_round_up, &env->fpu->fp_status); |
b6d96bed | 2346 | wt2 = float32_to_int32(fst0, &env->fpu->fp_status); |
fd4a04eb TS |
2347 | RESTORE_ROUNDING_MODE; |
2348 | update_fcr31(); | |
ead9360e | 2349 | if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) |
b6d96bed TS |
2350 | wt2 = FLOAT_SNAN32; |
2351 | return wt2; | |
fd4a04eb TS |
2352 | } |
2353 | ||
b6d96bed | 2354 | uint64_t do_float_floorl_d(uint64_t fdt0) |
fd4a04eb | 2355 | { |
b6d96bed TS |
2356 | uint64_t dt2; |
2357 | ||
ead9360e | 2358 | set_float_rounding_mode(float_round_down, &env->fpu->fp_status); |
b6d96bed | 2359 | dt2 = float64_to_int64(fdt0, &env->fpu->fp_status); |
fd4a04eb TS |
2360 | RESTORE_ROUNDING_MODE; |
2361 | update_fcr31(); | |
ead9360e | 2362 | if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) |
b6d96bed TS |
2363 | dt2 = FLOAT_SNAN64; |
2364 | return dt2; | |
fd4a04eb | 2365 | } |
b6d96bed TS |
2366 | |
2367 | uint64_t do_float_floorl_s(uint32_t fst0) | |
fd4a04eb | 2368 | { |
b6d96bed TS |
2369 | uint64_t dt2; |
2370 | ||
ead9360e | 2371 | set_float_rounding_mode(float_round_down, &env->fpu->fp_status); |
b6d96bed | 2372 | dt2 = float32_to_int64(fst0, &env->fpu->fp_status); |
fd4a04eb TS |
2373 | RESTORE_ROUNDING_MODE; |
2374 | update_fcr31(); | |
ead9360e | 2375 | if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) |
b6d96bed TS |
2376 | dt2 = FLOAT_SNAN64; |
2377 | return dt2; | |
fd4a04eb | 2378 | } |
b6d96bed TS |
2379 | |
2380 | uint32_t do_float_floorw_d(uint64_t fdt0) | |
fd4a04eb | 2381 | { |
b6d96bed TS |
2382 | uint32_t wt2; |
2383 | ||
ead9360e | 2384 | set_float_rounding_mode(float_round_down, &env->fpu->fp_status); |
b6d96bed | 2385 | wt2 = float64_to_int32(fdt0, &env->fpu->fp_status); |
fd4a04eb TS |
2386 | RESTORE_ROUNDING_MODE; |
2387 | update_fcr31(); | |
ead9360e | 2388 | if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) |
b6d96bed TS |
2389 | wt2 = FLOAT_SNAN32; |
2390 | return wt2; | |
fd4a04eb | 2391 | } |
b6d96bed TS |
2392 | |
2393 | uint32_t do_float_floorw_s(uint32_t fst0) | |
fd4a04eb | 2394 | { |
b6d96bed TS |
2395 | uint32_t wt2; |
2396 | ||
ead9360e | 2397 | set_float_rounding_mode(float_round_down, &env->fpu->fp_status); |
b6d96bed | 2398 | wt2 = float32_to_int32(fst0, &env->fpu->fp_status); |
fd4a04eb TS |
2399 | RESTORE_ROUNDING_MODE; |
2400 | update_fcr31(); | |
ead9360e | 2401 | if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) |
b6d96bed TS |
2402 | wt2 = FLOAT_SNAN32; |
2403 | return wt2; | |
fd4a04eb TS |
2404 | } |
2405 | ||
a16336e4 | 2406 | /* unary operations, not modifying fp status */ |
b6d96bed TS |
2407 | #define FLOAT_UNOP(name) \ |
2408 | uint64_t do_float_ ## name ## _d(uint64_t fdt0) \ | |
2409 | { \ | |
2410 | return float64_ ## name(fdt0); \ | |
2411 | } \ | |
2412 | uint32_t do_float_ ## name ## _s(uint32_t fst0) \ | |
2413 | { \ | |
2414 | return float32_ ## name(fst0); \ | |
2415 | } \ | |
2416 | uint64_t do_float_ ## name ## _ps(uint64_t fdt0) \ | |
2417 | { \ | |
2418 | uint32_t wt0; \ | |
2419 | uint32_t wth0; \ | |
2420 | \ | |
2421 | wt0 = float32_ ## name(fdt0 & 0XFFFFFFFF); \ | |
2422 | wth0 = float32_ ## name(fdt0 >> 32); \ | |
2423 | return ((uint64_t)wth0 << 32) | wt0; \ | |
a16336e4 TS |
2424 | } |
2425 | FLOAT_UNOP(abs) | |
2426 | FLOAT_UNOP(chs) | |
2427 | #undef FLOAT_UNOP | |
2428 | ||
8dfdb87c | 2429 | /* MIPS specific unary operations */ |
b6d96bed | 2430 | uint64_t do_float_recip_d(uint64_t fdt0) |
8dfdb87c | 2431 | { |
b6d96bed TS |
2432 | uint64_t fdt2; |
2433 | ||
ead9360e | 2434 | set_float_exception_flags(0, &env->fpu->fp_status); |
b6d96bed | 2435 | fdt2 = float64_div(FLOAT_ONE64, fdt0, &env->fpu->fp_status); |
8dfdb87c | 2436 | update_fcr31(); |
b6d96bed | 2437 | return fdt2; |
8dfdb87c | 2438 | } |
b6d96bed TS |
2439 | |
2440 | uint32_t do_float_recip_s(uint32_t fst0) | |
8dfdb87c | 2441 | { |
b6d96bed TS |
2442 | uint32_t fst2; |
2443 | ||
ead9360e | 2444 | set_float_exception_flags(0, &env->fpu->fp_status); |
b6d96bed | 2445 | fst2 = float32_div(FLOAT_ONE32, fst0, &env->fpu->fp_status); |
8dfdb87c | 2446 | update_fcr31(); |
b6d96bed | 2447 | return fst2; |
57fa1fb3 | 2448 | } |
57fa1fb3 | 2449 | |
b6d96bed | 2450 | uint64_t do_float_rsqrt_d(uint64_t fdt0) |
8dfdb87c | 2451 | { |
b6d96bed TS |
2452 | uint64_t fdt2; |
2453 | ||
ead9360e | 2454 | set_float_exception_flags(0, &env->fpu->fp_status); |
b6d96bed TS |
2455 | fdt2 = float64_sqrt(fdt0, &env->fpu->fp_status); |
2456 | fdt2 = float64_div(FLOAT_ONE64, fdt2, &env->fpu->fp_status); | |
8dfdb87c | 2457 | update_fcr31(); |
b6d96bed | 2458 | return fdt2; |
8dfdb87c | 2459 | } |
b6d96bed TS |
2460 | |
2461 | uint32_t do_float_rsqrt_s(uint32_t fst0) | |
8dfdb87c | 2462 | { |
b6d96bed TS |
2463 | uint32_t fst2; |
2464 | ||
ead9360e | 2465 | set_float_exception_flags(0, &env->fpu->fp_status); |
b6d96bed TS |
2466 | fst2 = float32_sqrt(fst0, &env->fpu->fp_status); |
2467 | fst2 = float32_div(FLOAT_ONE32, fst2, &env->fpu->fp_status); | |
8dfdb87c | 2468 | update_fcr31(); |
b6d96bed | 2469 | return fst2; |
8dfdb87c TS |
2470 | } |
2471 | ||
b6d96bed | 2472 | uint64_t do_float_recip1_d(uint64_t fdt0) |
8dfdb87c | 2473 | { |
b6d96bed TS |
2474 | uint64_t fdt2; |
2475 | ||
ead9360e | 2476 | set_float_exception_flags(0, &env->fpu->fp_status); |
b6d96bed | 2477 | fdt2 = float64_div(FLOAT_ONE64, fdt0, &env->fpu->fp_status); |
8dfdb87c | 2478 | update_fcr31(); |
b6d96bed | 2479 | return fdt2; |
8dfdb87c | 2480 | } |
b6d96bed TS |
2481 | |
2482 | uint32_t do_float_recip1_s(uint32_t fst0) | |
8dfdb87c | 2483 | { |
b6d96bed TS |
2484 | uint32_t fst2; |
2485 | ||
ead9360e | 2486 | set_float_exception_flags(0, &env->fpu->fp_status); |
b6d96bed | 2487 | fst2 = float32_div(FLOAT_ONE32, fst0, &env->fpu->fp_status); |
8dfdb87c | 2488 | update_fcr31(); |
b6d96bed | 2489 | return fst2; |
8dfdb87c | 2490 | } |
b6d96bed TS |
2491 | |
2492 | uint64_t do_float_recip1_ps(uint64_t fdt0) | |
8dfdb87c | 2493 | { |
b6d96bed TS |
2494 | uint32_t fst2; |
2495 | uint32_t fsth2; | |
2496 | ||
ead9360e | 2497 | set_float_exception_flags(0, &env->fpu->fp_status); |
b6d96bed TS |
2498 | fst2 = float32_div(FLOAT_ONE32, fdt0 & 0XFFFFFFFF, &env->fpu->fp_status); |
2499 | fsth2 = float32_div(FLOAT_ONE32, fdt0 >> 32, &env->fpu->fp_status); | |
8dfdb87c | 2500 | update_fcr31(); |
b6d96bed | 2501 | return ((uint64_t)fsth2 << 32) | fst2; |
8dfdb87c TS |
2502 | } |
2503 | ||
b6d96bed | 2504 | uint64_t do_float_rsqrt1_d(uint64_t fdt0) |
8dfdb87c | 2505 | { |
b6d96bed TS |
2506 | uint64_t fdt2; |
2507 | ||
ead9360e | 2508 | set_float_exception_flags(0, &env->fpu->fp_status); |
b6d96bed TS |
2509 | fdt2 = float64_sqrt(fdt0, &env->fpu->fp_status); |
2510 | fdt2 = float64_div(FLOAT_ONE64, fdt2, &env->fpu->fp_status); | |
8dfdb87c | 2511 | update_fcr31(); |
b6d96bed | 2512 | return fdt2; |
8dfdb87c | 2513 | } |
b6d96bed TS |
2514 | |
2515 | uint32_t do_float_rsqrt1_s(uint32_t fst0) | |
8dfdb87c | 2516 | { |
b6d96bed TS |
2517 | uint32_t fst2; |
2518 | ||
ead9360e | 2519 | set_float_exception_flags(0, &env->fpu->fp_status); |
b6d96bed TS |
2520 | fst2 = float32_sqrt(fst0, &env->fpu->fp_status); |
2521 | fst2 = float32_div(FLOAT_ONE32, fst2, &env->fpu->fp_status); | |
8dfdb87c | 2522 | update_fcr31(); |
b6d96bed | 2523 | return fst2; |
8dfdb87c | 2524 | } |
b6d96bed TS |
2525 | |
2526 | uint64_t do_float_rsqrt1_ps(uint64_t fdt0) | |
8dfdb87c | 2527 | { |
b6d96bed TS |
2528 | uint32_t fst2; |
2529 | uint32_t fsth2; | |
2530 | ||
ead9360e | 2531 | set_float_exception_flags(0, &env->fpu->fp_status); |
b6d96bed TS |
2532 | fst2 = float32_sqrt(fdt0 & 0XFFFFFFFF, &env->fpu->fp_status); |
2533 | fsth2 = float32_sqrt(fdt0 >> 32, &env->fpu->fp_status); | |
2534 | fst2 = float32_div(FLOAT_ONE32, fst2, &env->fpu->fp_status); | |
2535 | fsth2 = float32_div(FLOAT_ONE32, fsth2, &env->fpu->fp_status); | |
8dfdb87c | 2536 | update_fcr31(); |
b6d96bed | 2537 | return ((uint64_t)fsth2 << 32) | fst2; |
57fa1fb3 | 2538 | } |
57fa1fb3 | 2539 | |
b6d96bed TS |
2540 | #define FLOAT_OP(name, p) void do_float_##name##_##p(void) |
2541 | ||
fd4a04eb | 2542 | /* binary operations */ |
b6d96bed TS |
2543 | #define FLOAT_BINOP(name) \ |
2544 | uint64_t do_float_ ## name ## _d(uint64_t fdt0, uint64_t fdt1) \ | |
2545 | { \ | |
2546 | uint64_t dt2; \ | |
2547 | \ | |
ead9360e | 2548 | set_float_exception_flags(0, &env->fpu->fp_status); \ |
b6d96bed | 2549 | dt2 = float64_ ## name (fdt0, fdt1, &env->fpu->fp_status); \ |
ead9360e TS |
2550 | update_fcr31(); \ |
2551 | if (GET_FP_CAUSE(env->fpu->fcr31) & FP_INVALID) \ | |
b6d96bed TS |
2552 | dt2 = FLOAT_QNAN64; \ |
2553 | return dt2; \ | |
2554 | } \ | |
2555 | \ | |
2556 | uint32_t do_float_ ## name ## _s(uint32_t fst0, uint32_t fst1) \ | |
2557 | { \ | |
2558 | uint32_t wt2; \ | |
2559 | \ | |
ead9360e | 2560 | set_float_exception_flags(0, &env->fpu->fp_status); \ |
b6d96bed | 2561 | wt2 = float32_ ## name (fst0, fst1, &env->fpu->fp_status); \ |
ead9360e TS |
2562 | update_fcr31(); \ |
2563 | if (GET_FP_CAUSE(env->fpu->fcr31) & FP_INVALID) \ | |
b6d96bed TS |
2564 | wt2 = FLOAT_QNAN32; \ |
2565 | return wt2; \ | |
2566 | } \ | |
2567 | \ | |
2568 | uint64_t do_float_ ## name ## _ps(uint64_t fdt0, uint64_t fdt1) \ | |
2569 | { \ | |
2570 | uint32_t fst0 = fdt0 & 0XFFFFFFFF; \ | |
2571 | uint32_t fsth0 = fdt0 >> 32; \ | |
2572 | uint32_t fst1 = fdt1 & 0XFFFFFFFF; \ | |
2573 | uint32_t fsth1 = fdt1 >> 32; \ | |
2574 | uint32_t wt2; \ | |
2575 | uint32_t wth2; \ | |
2576 | \ | |
ead9360e | 2577 | set_float_exception_flags(0, &env->fpu->fp_status); \ |
b6d96bed TS |
2578 | wt2 = float32_ ## name (fst0, fst1, &env->fpu->fp_status); \ |
2579 | wth2 = float32_ ## name (fsth0, fsth1, &env->fpu->fp_status); \ | |
2580 | update_fcr31(); \ | |
ead9360e | 2581 | if (GET_FP_CAUSE(env->fpu->fcr31) & FP_INVALID) { \ |
b6d96bed TS |
2582 | wt2 = FLOAT_QNAN32; \ |
2583 | wth2 = FLOAT_QNAN32; \ | |
2584 | } \ | |
2585 | return ((uint64_t)wth2 << 32) | wt2; \ | |
fd4a04eb | 2586 | } |
b6d96bed | 2587 | |
fd4a04eb TS |
2588 | FLOAT_BINOP(add) |
2589 | FLOAT_BINOP(sub) | |
2590 | FLOAT_BINOP(mul) | |
2591 | FLOAT_BINOP(div) | |
2592 | #undef FLOAT_BINOP | |
2593 | ||
a16336e4 | 2594 | /* ternary operations */ |
b6d96bed TS |
2595 | #define FLOAT_TERNOP(name1, name2) \ |
2596 | uint64_t do_float_ ## name1 ## name2 ## _d(uint64_t fdt0, uint64_t fdt1, \ | |
2597 | uint64_t fdt2) \ | |
2598 | { \ | |
2599 | fdt0 = float64_ ## name1 (fdt0, fdt1, &env->fpu->fp_status); \ | |
2600 | return float64_ ## name2 (fdt0, fdt2, &env->fpu->fp_status); \ | |
2601 | } \ | |
2602 | \ | |
2603 | uint32_t do_float_ ## name1 ## name2 ## _s(uint32_t fst0, uint32_t fst1, \ | |
2604 | uint32_t fst2) \ | |
2605 | { \ | |
2606 | fst0 = float32_ ## name1 (fst0, fst1, &env->fpu->fp_status); \ | |
2607 | return float32_ ## name2 (fst0, fst2, &env->fpu->fp_status); \ | |
2608 | } \ | |
2609 | \ | |
2610 | uint64_t do_float_ ## name1 ## name2 ## _ps(uint64_t fdt0, uint64_t fdt1, \ | |
2611 | uint64_t fdt2) \ | |
2612 | { \ | |
2613 | uint32_t fst0 = fdt0 & 0XFFFFFFFF; \ | |
2614 | uint32_t fsth0 = fdt0 >> 32; \ | |
2615 | uint32_t fst1 = fdt1 & 0XFFFFFFFF; \ | |
2616 | uint32_t fsth1 = fdt1 >> 32; \ | |
2617 | uint32_t fst2 = fdt2 & 0XFFFFFFFF; \ | |
2618 | uint32_t fsth2 = fdt2 >> 32; \ | |
2619 | \ | |
2620 | fst0 = float32_ ## name1 (fst0, fst1, &env->fpu->fp_status); \ | |
2621 | fsth0 = float32_ ## name1 (fsth0, fsth1, &env->fpu->fp_status); \ | |
2622 | fst2 = float32_ ## name2 (fst0, fst2, &env->fpu->fp_status); \ | |
2623 | fsth2 = float32_ ## name2 (fsth0, fsth2, &env->fpu->fp_status); \ | |
2624 | return ((uint64_t)fsth2 << 32) | fst2; \ | |
a16336e4 | 2625 | } |
b6d96bed | 2626 | |
a16336e4 TS |
2627 | FLOAT_TERNOP(mul, add) |
2628 | FLOAT_TERNOP(mul, sub) | |
2629 | #undef FLOAT_TERNOP | |
2630 | ||
2631 | /* negated ternary operations */ | |
b6d96bed TS |
2632 | #define FLOAT_NTERNOP(name1, name2) \ |
2633 | uint64_t do_float_n ## name1 ## name2 ## _d(uint64_t fdt0, uint64_t fdt1, \ | |
2634 | uint64_t fdt2) \ | |
2635 | { \ | |
2636 | fdt0 = float64_ ## name1 (fdt0, fdt1, &env->fpu->fp_status); \ | |
2637 | fdt2 = float64_ ## name2 (fdt0, fdt2, &env->fpu->fp_status); \ | |
2638 | return float64_chs(fdt2); \ | |
2639 | } \ | |
2640 | \ | |
2641 | uint32_t do_float_n ## name1 ## name2 ## _s(uint32_t fst0, uint32_t fst1, \ | |
2642 | uint32_t fst2) \ | |
2643 | { \ | |
2644 | fst0 = float32_ ## name1 (fst0, fst1, &env->fpu->fp_status); \ | |
2645 | fst2 = float32_ ## name2 (fst0, fst2, &env->fpu->fp_status); \ | |
2646 | return float32_chs(fst2); \ | |
2647 | } \ | |
2648 | \ | |
2649 | uint64_t do_float_n ## name1 ## name2 ## _ps(uint64_t fdt0, uint64_t fdt1,\ | |
2650 | uint64_t fdt2) \ | |
2651 | { \ | |
2652 | uint32_t fst0 = fdt0 & 0XFFFFFFFF; \ | |
2653 | uint32_t fsth0 = fdt0 >> 32; \ | |
2654 | uint32_t fst1 = fdt1 & 0XFFFFFFFF; \ | |
2655 | uint32_t fsth1 = fdt1 >> 32; \ | |
2656 | uint32_t fst2 = fdt2 & 0XFFFFFFFF; \ | |
2657 | uint32_t fsth2 = fdt2 >> 32; \ | |
2658 | \ | |
2659 | fst0 = float32_ ## name1 (fst0, fst1, &env->fpu->fp_status); \ | |
2660 | fsth0 = float32_ ## name1 (fsth0, fsth1, &env->fpu->fp_status); \ | |
2661 | fst2 = float32_ ## name2 (fst0, fst2, &env->fpu->fp_status); \ | |
2662 | fsth2 = float32_ ## name2 (fsth0, fsth2, &env->fpu->fp_status); \ | |
2663 | fst2 = float32_chs(fst2); \ | |
2664 | fsth2 = float32_chs(fsth2); \ | |
2665 | return ((uint64_t)fsth2 << 32) | fst2; \ | |
a16336e4 | 2666 | } |
b6d96bed | 2667 | |
a16336e4 TS |
2668 | FLOAT_NTERNOP(mul, add) |
2669 | FLOAT_NTERNOP(mul, sub) | |
2670 | #undef FLOAT_NTERNOP | |
2671 | ||
8dfdb87c | 2672 | /* MIPS specific binary operations */ |
b6d96bed | 2673 | uint64_t do_float_recip2_d(uint64_t fdt0, uint64_t fdt2) |
8dfdb87c | 2674 | { |
ead9360e | 2675 | set_float_exception_flags(0, &env->fpu->fp_status); |
b6d96bed TS |
2676 | fdt2 = float64_mul(fdt0, fdt2, &env->fpu->fp_status); |
2677 | fdt2 = float64_chs(float64_sub(fdt2, FLOAT_ONE64, &env->fpu->fp_status)); | |
8dfdb87c | 2678 | update_fcr31(); |
b6d96bed | 2679 | return fdt2; |
8dfdb87c | 2680 | } |
b6d96bed TS |
2681 | |
2682 | uint32_t do_float_recip2_s(uint32_t fst0, uint32_t fst2) | |
8dfdb87c | 2683 | { |
ead9360e | 2684 | set_float_exception_flags(0, &env->fpu->fp_status); |
b6d96bed TS |
2685 | fst2 = float32_mul(fst0, fst2, &env->fpu->fp_status); |
2686 | fst2 = float32_chs(float32_sub(fst2, FLOAT_ONE32, &env->fpu->fp_status)); | |
8dfdb87c | 2687 | update_fcr31(); |
b6d96bed | 2688 | return fst2; |
8dfdb87c | 2689 | } |
b6d96bed TS |
2690 | |
2691 | uint64_t do_float_recip2_ps(uint64_t fdt0, uint64_t fdt2) | |
8dfdb87c | 2692 | { |
b6d96bed TS |
2693 | uint32_t fst0 = fdt0 & 0XFFFFFFFF; |
2694 | uint32_t fsth0 = fdt0 >> 32; | |
2695 | uint32_t fst2 = fdt2 & 0XFFFFFFFF; | |
2696 | uint32_t fsth2 = fdt2 >> 32; | |
2697 | ||
ead9360e | 2698 | set_float_exception_flags(0, &env->fpu->fp_status); |
b6d96bed TS |
2699 | fst2 = float32_mul(fst0, fst2, &env->fpu->fp_status); |
2700 | fsth2 = float32_mul(fsth0, fsth2, &env->fpu->fp_status); | |
2701 | fst2 = float32_chs(float32_sub(fst2, FLOAT_ONE32, &env->fpu->fp_status)); | |
2702 | fsth2 = float32_chs(float32_sub(fsth2, FLOAT_ONE32, &env->fpu->fp_status)); | |
8dfdb87c | 2703 | update_fcr31(); |
b6d96bed | 2704 | return ((uint64_t)fsth2 << 32) | fst2; |
8dfdb87c TS |
2705 | } |
2706 | ||
b6d96bed | 2707 | uint64_t do_float_rsqrt2_d(uint64_t fdt0, uint64_t fdt2) |
8dfdb87c | 2708 | { |
ead9360e | 2709 | set_float_exception_flags(0, &env->fpu->fp_status); |
b6d96bed TS |
2710 | fdt2 = float64_mul(fdt0, fdt2, &env->fpu->fp_status); |
2711 | fdt2 = float64_sub(fdt2, FLOAT_ONE64, &env->fpu->fp_status); | |
2712 | fdt2 = float64_chs(float64_div(fdt2, FLOAT_TWO64, &env->fpu->fp_status)); | |
8dfdb87c | 2713 | update_fcr31(); |
b6d96bed | 2714 | return fdt2; |
8dfdb87c | 2715 | } |
b6d96bed TS |
2716 | |
2717 | uint32_t do_float_rsqrt2_s(uint32_t fst0, uint32_t fst2) | |
8dfdb87c | 2718 | { |
ead9360e | 2719 | set_float_exception_flags(0, &env->fpu->fp_status); |
b6d96bed TS |
2720 | fst2 = float32_mul(fst0, fst2, &env->fpu->fp_status); |
2721 | fst2 = float32_sub(fst2, FLOAT_ONE32, &env->fpu->fp_status); | |
2722 | fst2 = float32_chs(float32_div(fst2, FLOAT_TWO32, &env->fpu->fp_status)); | |
8dfdb87c | 2723 | update_fcr31(); |
b6d96bed | 2724 | return fst2; |
8dfdb87c | 2725 | } |
b6d96bed TS |
2726 | |
2727 | uint64_t do_float_rsqrt2_ps(uint64_t fdt0, uint64_t fdt2) | |
8dfdb87c | 2728 | { |
b6d96bed TS |
2729 | uint32_t fst0 = fdt0 & 0XFFFFFFFF; |
2730 | uint32_t fsth0 = fdt0 >> 32; | |
2731 | uint32_t fst2 = fdt2 & 0XFFFFFFFF; | |
2732 | uint32_t fsth2 = fdt2 >> 32; | |
2733 | ||
ead9360e | 2734 | set_float_exception_flags(0, &env->fpu->fp_status); |
b6d96bed TS |
2735 | fst2 = float32_mul(fst0, fst2, &env->fpu->fp_status); |
2736 | fsth2 = float32_mul(fsth0, fsth2, &env->fpu->fp_status); | |
2737 | fst2 = float32_sub(fst2, FLOAT_ONE32, &env->fpu->fp_status); | |
2738 | fsth2 = float32_sub(fsth2, FLOAT_ONE32, &env->fpu->fp_status); | |
2739 | fst2 = float32_chs(float32_div(fst2, FLOAT_TWO32, &env->fpu->fp_status)); | |
2740 | fsth2 = float32_chs(float32_div(fsth2, FLOAT_TWO32, &env->fpu->fp_status)); | |
8dfdb87c | 2741 | update_fcr31(); |
b6d96bed | 2742 | return ((uint64_t)fsth2 << 32) | fst2; |
57fa1fb3 | 2743 | } |
57fa1fb3 | 2744 | |
b6d96bed | 2745 | uint64_t do_float_addr_ps(uint64_t fdt0, uint64_t fdt1) |
fd4a04eb | 2746 | { |
b6d96bed TS |
2747 | uint32_t fst0 = fdt0 & 0XFFFFFFFF; |
2748 | uint32_t fsth0 = fdt0 >> 32; | |
2749 | uint32_t fst1 = fdt1 & 0XFFFFFFFF; | |
2750 | uint32_t fsth1 = fdt1 >> 32; | |
2751 | uint32_t fst2; | |
2752 | uint32_t fsth2; | |
2753 | ||
ead9360e | 2754 | set_float_exception_flags(0, &env->fpu->fp_status); |
b6d96bed TS |
2755 | fst2 = float32_add (fst0, fsth0, &env->fpu->fp_status); |
2756 | fsth2 = float32_add (fst1, fsth1, &env->fpu->fp_status); | |
fd4a04eb | 2757 | update_fcr31(); |
b6d96bed | 2758 | return ((uint64_t)fsth2 << 32) | fst2; |
fd4a04eb TS |
2759 | } |
2760 | ||
b6d96bed | 2761 | uint64_t do_float_mulr_ps(uint64_t fdt0, uint64_t fdt1) |
57fa1fb3 | 2762 | { |
b6d96bed TS |
2763 | uint32_t fst0 = fdt0 & 0XFFFFFFFF; |
2764 | uint32_t fsth0 = fdt0 >> 32; | |
2765 | uint32_t fst1 = fdt1 & 0XFFFFFFFF; | |
2766 | uint32_t fsth1 = fdt1 >> 32; | |
2767 | uint32_t fst2; | |
2768 | uint32_t fsth2; | |
2769 | ||
ead9360e | 2770 | set_float_exception_flags(0, &env->fpu->fp_status); |
b6d96bed TS |
2771 | fst2 = float32_mul (fst0, fsth0, &env->fpu->fp_status); |
2772 | fsth2 = float32_mul (fst1, fsth1, &env->fpu->fp_status); | |
57fa1fb3 | 2773 | update_fcr31(); |
b6d96bed | 2774 | return ((uint64_t)fsth2 << 32) | fst2; |
57fa1fb3 TS |
2775 | } |
2776 | ||
8dfdb87c | 2777 | /* compare operations */ |
b6d96bed TS |
2778 | #define FOP_COND_D(op, cond) \ |
2779 | void do_cmp_d_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \ | |
2780 | { \ | |
2781 | int c = cond; \ | |
2782 | update_fcr31(); \ | |
2783 | if (c) \ | |
2784 | SET_FP_COND(cc, env->fpu); \ | |
2785 | else \ | |
2786 | CLEAR_FP_COND(cc, env->fpu); \ | |
2787 | } \ | |
2788 | void do_cmpabs_d_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \ | |
2789 | { \ | |
2790 | int c; \ | |
2791 | fdt0 = float64_abs(fdt0); \ | |
2792 | fdt1 = float64_abs(fdt1); \ | |
2793 | c = cond; \ | |
2794 | update_fcr31(); \ | |
2795 | if (c) \ | |
2796 | SET_FP_COND(cc, env->fpu); \ | |
2797 | else \ | |
2798 | CLEAR_FP_COND(cc, env->fpu); \ | |
fd4a04eb TS |
2799 | } |
2800 | ||
2801 | int float64_is_unordered(int sig, float64 a, float64 b STATUS_PARAM) | |
2802 | { | |
2803 | if (float64_is_signaling_nan(a) || | |
2804 | float64_is_signaling_nan(b) || | |
2805 | (sig && (float64_is_nan(a) || float64_is_nan(b)))) { | |
2806 | float_raise(float_flag_invalid, status); | |
2807 | return 1; | |
2808 | } else if (float64_is_nan(a) || float64_is_nan(b)) { | |
2809 | return 1; | |
2810 | } else { | |
2811 | return 0; | |
2812 | } | |
2813 | } | |
2814 | ||
2815 | /* NOTE: the comma operator will make "cond" to eval to false, | |
2816 | * but float*_is_unordered() is still called. */ | |
b6d96bed TS |
2817 | FOP_COND_D(f, (float64_is_unordered(0, fdt1, fdt0, &env->fpu->fp_status), 0)) |
2818 | FOP_COND_D(un, float64_is_unordered(0, fdt1, fdt0, &env->fpu->fp_status)) | |
2819 | FOP_COND_D(eq, !float64_is_unordered(0, fdt1, fdt0, &env->fpu->fp_status) && float64_eq(fdt0, fdt1, &env->fpu->fp_status)) | |
2820 | FOP_COND_D(ueq, float64_is_unordered(0, fdt1, fdt0, &env->fpu->fp_status) || float64_eq(fdt0, fdt1, &env->fpu->fp_status)) | |
2821 | FOP_COND_D(olt, !float64_is_unordered(0, fdt1, fdt0, &env->fpu->fp_status) && float64_lt(fdt0, fdt1, &env->fpu->fp_status)) | |
2822 | FOP_COND_D(ult, float64_is_unordered(0, fdt1, fdt0, &env->fpu->fp_status) || float64_lt(fdt0, fdt1, &env->fpu->fp_status)) | |
2823 | FOP_COND_D(ole, !float64_is_unordered(0, fdt1, fdt0, &env->fpu->fp_status) && float64_le(fdt0, fdt1, &env->fpu->fp_status)) | |
2824 | FOP_COND_D(ule, float64_is_unordered(0, fdt1, fdt0, &env->fpu->fp_status) || float64_le(fdt0, fdt1, &env->fpu->fp_status)) | |
fd4a04eb TS |
2825 | /* NOTE: the comma operator will make "cond" to eval to false, |
2826 | * but float*_is_unordered() is still called. */ | |
b6d96bed TS |
2827 | FOP_COND_D(sf, (float64_is_unordered(1, fdt1, fdt0, &env->fpu->fp_status), 0)) |
2828 | FOP_COND_D(ngle,float64_is_unordered(1, fdt1, fdt0, &env->fpu->fp_status)) | |
2829 | FOP_COND_D(seq, !float64_is_unordered(1, fdt1, fdt0, &env->fpu->fp_status) && float64_eq(fdt0, fdt1, &env->fpu->fp_status)) | |
2830 | FOP_COND_D(ngl, float64_is_unordered(1, fdt1, fdt0, &env->fpu->fp_status) || float64_eq(fdt0, fdt1, &env->fpu->fp_status)) | |
2831 | FOP_COND_D(lt, !float64_is_unordered(1, fdt1, fdt0, &env->fpu->fp_status) && float64_lt(fdt0, fdt1, &env->fpu->fp_status)) | |
2832 | FOP_COND_D(nge, float64_is_unordered(1, fdt1, fdt0, &env->fpu->fp_status) || float64_lt(fdt0, fdt1, &env->fpu->fp_status)) | |
2833 | FOP_COND_D(le, !float64_is_unordered(1, fdt1, fdt0, &env->fpu->fp_status) && float64_le(fdt0, fdt1, &env->fpu->fp_status)) | |
2834 | FOP_COND_D(ngt, float64_is_unordered(1, fdt1, fdt0, &env->fpu->fp_status) || float64_le(fdt0, fdt1, &env->fpu->fp_status)) | |
2835 | ||
2836 | #define FOP_COND_S(op, cond) \ | |
2837 | void do_cmp_s_ ## op (uint32_t fst0, uint32_t fst1, int cc) \ | |
2838 | { \ | |
2839 | int c = cond; \ | |
2840 | update_fcr31(); \ | |
2841 | if (c) \ | |
2842 | SET_FP_COND(cc, env->fpu); \ | |
2843 | else \ | |
2844 | CLEAR_FP_COND(cc, env->fpu); \ | |
2845 | } \ | |
2846 | void do_cmpabs_s_ ## op (uint32_t fst0, uint32_t fst1, int cc) \ | |
2847 | { \ | |
2848 | int c; \ | |
2849 | fst0 = float32_abs(fst0); \ | |
2850 | fst1 = float32_abs(fst1); \ | |
2851 | c = cond; \ | |
2852 | update_fcr31(); \ | |
2853 | if (c) \ | |
2854 | SET_FP_COND(cc, env->fpu); \ | |
2855 | else \ | |
2856 | CLEAR_FP_COND(cc, env->fpu); \ | |
fd4a04eb TS |
2857 | } |
2858 | ||
2859 | flag float32_is_unordered(int sig, float32 a, float32 b STATUS_PARAM) | |
2860 | { | |
fd4a04eb TS |
2861 | if (float32_is_signaling_nan(a) || |
2862 | float32_is_signaling_nan(b) || | |
2863 | (sig && (float32_is_nan(a) || float32_is_nan(b)))) { | |
2864 | float_raise(float_flag_invalid, status); | |
2865 | return 1; | |
2866 | } else if (float32_is_nan(a) || float32_is_nan(b)) { | |
2867 | return 1; | |
2868 | } else { | |
2869 | return 0; | |
2870 | } | |
2871 | } | |
2872 | ||
2873 | /* NOTE: the comma operator will make "cond" to eval to false, | |
2874 | * but float*_is_unordered() is still called. */ | |
b6d96bed TS |
2875 | FOP_COND_S(f, (float32_is_unordered(0, fst1, fst0, &env->fpu->fp_status), 0)) |
2876 | FOP_COND_S(un, float32_is_unordered(0, fst1, fst0, &env->fpu->fp_status)) | |
2877 | FOP_COND_S(eq, !float32_is_unordered(0, fst1, fst0, &env->fpu->fp_status) && float32_eq(fst0, fst1, &env->fpu->fp_status)) | |
2878 | FOP_COND_S(ueq, float32_is_unordered(0, fst1, fst0, &env->fpu->fp_status) || float32_eq(fst0, fst1, &env->fpu->fp_status)) | |
2879 | FOP_COND_S(olt, !float32_is_unordered(0, fst1, fst0, &env->fpu->fp_status) && float32_lt(fst0, fst1, &env->fpu->fp_status)) | |
2880 | FOP_COND_S(ult, float32_is_unordered(0, fst1, fst0, &env->fpu->fp_status) || float32_lt(fst0, fst1, &env->fpu->fp_status)) | |
2881 | FOP_COND_S(ole, !float32_is_unordered(0, fst1, fst0, &env->fpu->fp_status) && float32_le(fst0, fst1, &env->fpu->fp_status)) | |
2882 | FOP_COND_S(ule, float32_is_unordered(0, fst1, fst0, &env->fpu->fp_status) || float32_le(fst0, fst1, &env->fpu->fp_status)) | |
fd4a04eb TS |
2883 | /* NOTE: the comma operator will make "cond" to eval to false, |
2884 | * but float*_is_unordered() is still called. */ | |
b6d96bed TS |
2885 | FOP_COND_S(sf, (float32_is_unordered(1, fst1, fst0, &env->fpu->fp_status), 0)) |
2886 | FOP_COND_S(ngle,float32_is_unordered(1, fst1, fst0, &env->fpu->fp_status)) | |
2887 | FOP_COND_S(seq, !float32_is_unordered(1, fst1, fst0, &env->fpu->fp_status) && float32_eq(fst0, fst1, &env->fpu->fp_status)) | |
2888 | FOP_COND_S(ngl, float32_is_unordered(1, fst1, fst0, &env->fpu->fp_status) || float32_eq(fst0, fst1, &env->fpu->fp_status)) | |
2889 | FOP_COND_S(lt, !float32_is_unordered(1, fst1, fst0, &env->fpu->fp_status) && float32_lt(fst0, fst1, &env->fpu->fp_status)) | |
2890 | FOP_COND_S(nge, float32_is_unordered(1, fst1, fst0, &env->fpu->fp_status) || float32_lt(fst0, fst1, &env->fpu->fp_status)) | |
2891 | FOP_COND_S(le, !float32_is_unordered(1, fst1, fst0, &env->fpu->fp_status) && float32_le(fst0, fst1, &env->fpu->fp_status)) | |
2892 | FOP_COND_S(ngt, float32_is_unordered(1, fst1, fst0, &env->fpu->fp_status) || float32_le(fst0, fst1, &env->fpu->fp_status)) | |
2893 | ||
2894 | #define FOP_COND_PS(op, condl, condh) \ | |
2895 | void do_cmp_ps_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \ | |
2896 | { \ | |
2897 | uint32_t fst0 = float32_abs(fdt0 & 0XFFFFFFFF); \ | |
2898 | uint32_t fsth0 = float32_abs(fdt0 >> 32); \ | |
2899 | uint32_t fst1 = float32_abs(fdt1 & 0XFFFFFFFF); \ | |
2900 | uint32_t fsth1 = float32_abs(fdt1 >> 32); \ | |
2901 | int cl = condl; \ | |
2902 | int ch = condh; \ | |
2903 | \ | |
2904 | update_fcr31(); \ | |
2905 | if (cl) \ | |
2906 | SET_FP_COND(cc, env->fpu); \ | |
2907 | else \ | |
2908 | CLEAR_FP_COND(cc, env->fpu); \ | |
2909 | if (ch) \ | |
2910 | SET_FP_COND(cc + 1, env->fpu); \ | |
2911 | else \ | |
2912 | CLEAR_FP_COND(cc + 1, env->fpu); \ | |
2913 | } \ | |
2914 | void do_cmpabs_ps_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \ | |
2915 | { \ | |
2916 | uint32_t fst0 = float32_abs(fdt0 & 0XFFFFFFFF); \ | |
2917 | uint32_t fsth0 = float32_abs(fdt0 >> 32); \ | |
2918 | uint32_t fst1 = float32_abs(fdt1 & 0XFFFFFFFF); \ | |
2919 | uint32_t fsth1 = float32_abs(fdt1 >> 32); \ | |
2920 | int cl = condl; \ | |
2921 | int ch = condh; \ | |
2922 | \ | |
2923 | update_fcr31(); \ | |
2924 | if (cl) \ | |
2925 | SET_FP_COND(cc, env->fpu); \ | |
2926 | else \ | |
2927 | CLEAR_FP_COND(cc, env->fpu); \ | |
2928 | if (ch) \ | |
2929 | SET_FP_COND(cc + 1, env->fpu); \ | |
2930 | else \ | |
2931 | CLEAR_FP_COND(cc + 1, env->fpu); \ | |
fd4a04eb TS |
2932 | } |
2933 | ||
2934 | /* NOTE: the comma operator will make "cond" to eval to false, | |
2935 | * but float*_is_unordered() is still called. */ | |
b6d96bed TS |
2936 | FOP_COND_PS(f, (float32_is_unordered(0, fst1, fst0, &env->fpu->fp_status), 0), |
2937 | (float32_is_unordered(0, fsth1, fsth0, &env->fpu->fp_status), 0)) | |
2938 | FOP_COND_PS(un, float32_is_unordered(0, fst1, fst0, &env->fpu->fp_status), | |
2939 | float32_is_unordered(0, fsth1, fsth0, &env->fpu->fp_status)) | |
2940 | FOP_COND_PS(eq, !float32_is_unordered(0, fst1, fst0, &env->fpu->fp_status) && float32_eq(fst0, fst1, &env->fpu->fp_status), | |
2941 | !float32_is_unordered(0, fsth1, fsth0, &env->fpu->fp_status) && float32_eq(fsth0, fsth1, &env->fpu->fp_status)) | |
2942 | FOP_COND_PS(ueq, float32_is_unordered(0, fst1, fst0, &env->fpu->fp_status) || float32_eq(fst0, fst1, &env->fpu->fp_status), | |
2943 | float32_is_unordered(0, fsth1, fsth0, &env->fpu->fp_status) || float32_eq(fsth0, fsth1, &env->fpu->fp_status)) | |
2944 | FOP_COND_PS(olt, !float32_is_unordered(0, fst1, fst0, &env->fpu->fp_status) && float32_lt(fst0, fst1, &env->fpu->fp_status), | |
2945 | !float32_is_unordered(0, fsth1, fsth0, &env->fpu->fp_status) && float32_lt(fsth0, fsth1, &env->fpu->fp_status)) | |
2946 | FOP_COND_PS(ult, float32_is_unordered(0, fst1, fst0, &env->fpu->fp_status) || float32_lt(fst0, fst1, &env->fpu->fp_status), | |
2947 | float32_is_unordered(0, fsth1, fsth0, &env->fpu->fp_status) || float32_lt(fsth0, fsth1, &env->fpu->fp_status)) | |
2948 | FOP_COND_PS(ole, !float32_is_unordered(0, fst1, fst0, &env->fpu->fp_status) && float32_le(fst0, fst1, &env->fpu->fp_status), | |
2949 | !float32_is_unordered(0, fsth1, fsth0, &env->fpu->fp_status) && float32_le(fsth0, fsth1, &env->fpu->fp_status)) | |
2950 | FOP_COND_PS(ule, float32_is_unordered(0, fst1, fst0, &env->fpu->fp_status) || float32_le(fst0, fst1, &env->fpu->fp_status), | |
2951 | float32_is_unordered(0, fsth1, fsth0, &env->fpu->fp_status) || float32_le(fsth0, fsth1, &env->fpu->fp_status)) | |
fd4a04eb TS |
2952 | /* NOTE: the comma operator will make "cond" to eval to false, |
2953 | * but float*_is_unordered() is still called. */ | |
b6d96bed TS |
2954 | FOP_COND_PS(sf, (float32_is_unordered(1, fst1, fst0, &env->fpu->fp_status), 0), |
2955 | (float32_is_unordered(1, fsth1, fsth0, &env->fpu->fp_status), 0)) | |
2956 | FOP_COND_PS(ngle,float32_is_unordered(1, fst1, fst0, &env->fpu->fp_status), | |
2957 | float32_is_unordered(1, fsth1, fsth0, &env->fpu->fp_status)) | |
2958 | FOP_COND_PS(seq, !float32_is_unordered(1, fst1, fst0, &env->fpu->fp_status) && float32_eq(fst0, fst1, &env->fpu->fp_status), | |
2959 | !float32_is_unordered(1, fsth1, fsth0, &env->fpu->fp_status) && float32_eq(fsth0, fsth1, &env->fpu->fp_status)) | |
2960 | FOP_COND_PS(ngl, float32_is_unordered(1, fst1, fst0, &env->fpu->fp_status) || float32_eq(fst0, fst1, &env->fpu->fp_status), | |
2961 | float32_is_unordered(1, fsth1, fsth0, &env->fpu->fp_status) || float32_eq(fsth0, fsth1, &env->fpu->fp_status)) | |
2962 | FOP_COND_PS(lt, !float32_is_unordered(1, fst1, fst0, &env->fpu->fp_status) && float32_lt(fst0, fst1, &env->fpu->fp_status), | |
2963 | !float32_is_unordered(1, fsth1, fsth0, &env->fpu->fp_status) && float32_lt(fsth0, fsth1, &env->fpu->fp_status)) | |
2964 | FOP_COND_PS(nge, float32_is_unordered(1, fst1, fst0, &env->fpu->fp_status) || float32_lt(fst0, fst1, &env->fpu->fp_status), | |
2965 | float32_is_unordered(1, fsth1, fsth0, &env->fpu->fp_status) || float32_lt(fsth0, fsth1, &env->fpu->fp_status)) | |
2966 | FOP_COND_PS(le, !float32_is_unordered(1, fst1, fst0, &env->fpu->fp_status) && float32_le(fst0, fst1, &env->fpu->fp_status), | |
2967 | !float32_is_unordered(1, fsth1, fsth0, &env->fpu->fp_status) && float32_le(fsth0, fsth1, &env->fpu->fp_status)) | |
2968 | FOP_COND_PS(ngt, float32_is_unordered(1, fst1, fst0, &env->fpu->fp_status) || float32_le(fst0, fst1, &env->fpu->fp_status), | |
2969 | float32_is_unordered(1, fsth1, fsth0, &env->fpu->fp_status) || float32_le(fsth0, fsth1, &env->fpu->fp_status)) |