]> git.proxmox.com Git - mirror_qemu.git/blob - target-mips/op.c
2c99ad754d775f5480982d91f3742490ce4310e1
[mirror_qemu.git] / target-mips / op.c
1 /*
2 * MIPS emulation micro-operations for qemu.
3 *
4 * Copyright (c) 2004-2005 Jocelyn Mayer
5 * Copyright (c) 2006 Marius Groeger (FPU operations)
6 * Copyright (c) 2007 Thiemo Seufer (64-bit FPU support)
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23 #include "config.h"
24 #include "exec.h"
25 #include "host-utils.h"
26
27 #ifndef CALL_FROM_TB0
28 #define CALL_FROM_TB0(func) func()
29 #endif
30 #ifndef CALL_FROM_TB1
31 #define CALL_FROM_TB1(func, arg0) func(arg0)
32 #endif
33 #ifndef CALL_FROM_TB1_CONST16
34 #define CALL_FROM_TB1_CONST16(func, arg0) CALL_FROM_TB1(func, arg0)
35 #endif
36 #ifndef CALL_FROM_TB2
37 #define CALL_FROM_TB2(func, arg0, arg1) func(arg0, arg1)
38 #endif
39 #ifndef CALL_FROM_TB2_CONST16
40 #define CALL_FROM_TB2_CONST16(func, arg0, arg1) \
41 CALL_FROM_TB2(func, arg0, arg1)
42 #endif
43 #ifndef CALL_FROM_TB3
44 #define CALL_FROM_TB3(func, arg0, arg1, arg2) func(arg0, arg1, arg2)
45 #endif
46 #ifndef CALL_FROM_TB4
47 #define CALL_FROM_TB4(func, arg0, arg1, arg2, arg3) \
48 func(arg0, arg1, arg2, arg3)
49 #endif
50
51 /* Load and store */
52 #define MEMSUFFIX _raw
53 #include "op_mem.c"
54 #undef MEMSUFFIX
55 #if !defined(CONFIG_USER_ONLY)
56 #define MEMSUFFIX _user
57 #include "op_mem.c"
58 #undef MEMSUFFIX
59
60 #define MEMSUFFIX _super
61 #include "op_mem.c"
62 #undef MEMSUFFIX
63
64 #define MEMSUFFIX _kernel
65 #include "op_mem.c"
66 #undef MEMSUFFIX
67 #endif
68
69 /* 64 bits arithmetic */
70 #if TARGET_LONG_BITS > HOST_LONG_BITS
71 void op_madd (void)
72 {
73 CALL_FROM_TB0(do_madd);
74 FORCE_RET();
75 }
76
77 void op_maddu (void)
78 {
79 CALL_FROM_TB0(do_maddu);
80 FORCE_RET();
81 }
82
83 void op_msub (void)
84 {
85 CALL_FROM_TB0(do_msub);
86 FORCE_RET();
87 }
88
89 void op_msubu (void)
90 {
91 CALL_FROM_TB0(do_msubu);
92 FORCE_RET();
93 }
94
95 /* Multiplication variants of the vr54xx. */
96 void op_muls (void)
97 {
98 CALL_FROM_TB0(do_muls);
99 FORCE_RET();
100 }
101
102 void op_mulsu (void)
103 {
104 CALL_FROM_TB0(do_mulsu);
105 FORCE_RET();
106 }
107
108 void op_macc (void)
109 {
110 CALL_FROM_TB0(do_macc);
111 FORCE_RET();
112 }
113
114 void op_macchi (void)
115 {
116 CALL_FROM_TB0(do_macchi);
117 FORCE_RET();
118 }
119
120 void op_maccu (void)
121 {
122 CALL_FROM_TB0(do_maccu);
123 FORCE_RET();
124 }
125 void op_macchiu (void)
126 {
127 CALL_FROM_TB0(do_macchiu);
128 FORCE_RET();
129 }
130
131 void op_msac (void)
132 {
133 CALL_FROM_TB0(do_msac);
134 FORCE_RET();
135 }
136
137 void op_msachi (void)
138 {
139 CALL_FROM_TB0(do_msachi);
140 FORCE_RET();
141 }
142
143 void op_msacu (void)
144 {
145 CALL_FROM_TB0(do_msacu);
146 FORCE_RET();
147 }
148
149 void op_msachiu (void)
150 {
151 CALL_FROM_TB0(do_msachiu);
152 FORCE_RET();
153 }
154
155 void op_mulhi (void)
156 {
157 CALL_FROM_TB0(do_mulhi);
158 FORCE_RET();
159 }
160
161 void op_mulhiu (void)
162 {
163 CALL_FROM_TB0(do_mulhiu);
164 FORCE_RET();
165 }
166
167 void op_mulshi (void)
168 {
169 CALL_FROM_TB0(do_mulshi);
170 FORCE_RET();
171 }
172
173 void op_mulshiu (void)
174 {
175 CALL_FROM_TB0(do_mulshiu);
176 FORCE_RET();
177 }
178
179 #else /* TARGET_LONG_BITS > HOST_LONG_BITS */
180
181 static always_inline uint64_t get_HILO (void)
182 {
183 return ((uint64_t)env->HI[env->current_tc][0] << 32) |
184 ((uint64_t)(uint32_t)env->LO[env->current_tc][0]);
185 }
186
187 static always_inline void set_HILO (uint64_t HILO)
188 {
189 env->LO[env->current_tc][0] = (int32_t)(HILO & 0xFFFFFFFF);
190 env->HI[env->current_tc][0] = (int32_t)(HILO >> 32);
191 }
192
193 static always_inline void set_HIT0_LO (uint64_t HILO)
194 {
195 env->LO[env->current_tc][0] = (int32_t)(HILO & 0xFFFFFFFF);
196 T0 = env->HI[env->current_tc][0] = (int32_t)(HILO >> 32);
197 }
198
199 static always_inline void set_HI_LOT0 (uint64_t HILO)
200 {
201 T0 = env->LO[env->current_tc][0] = (int32_t)(HILO & 0xFFFFFFFF);
202 env->HI[env->current_tc][0] = (int32_t)(HILO >> 32);
203 }
204
205 /* Multiplication variants of the vr54xx. */
206 void op_muls (void)
207 {
208 set_HI_LOT0(0 - ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1));
209 FORCE_RET();
210 }
211
212 void op_mulsu (void)
213 {
214 set_HI_LOT0(0 - ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1));
215 FORCE_RET();
216 }
217
218 void op_macc (void)
219 {
220 set_HI_LOT0(get_HILO() + ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1));
221 FORCE_RET();
222 }
223
224 void op_macchi (void)
225 {
226 set_HIT0_LO(get_HILO() + ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1));
227 FORCE_RET();
228 }
229
230 void op_maccu (void)
231 {
232 set_HI_LOT0(get_HILO() + ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1));
233 FORCE_RET();
234 }
235
236 void op_macchiu (void)
237 {
238 set_HIT0_LO(get_HILO() + ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1));
239 FORCE_RET();
240 }
241
242 void op_msac (void)
243 {
244 set_HI_LOT0(get_HILO() - ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1));
245 FORCE_RET();
246 }
247
248 void op_msachi (void)
249 {
250 set_HIT0_LO(get_HILO() - ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1));
251 FORCE_RET();
252 }
253
254 void op_msacu (void)
255 {
256 set_HI_LOT0(get_HILO() - ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1));
257 FORCE_RET();
258 }
259
260 void op_msachiu (void)
261 {
262 set_HIT0_LO(get_HILO() - ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1));
263 FORCE_RET();
264 }
265
266 void op_mulhi (void)
267 {
268 set_HIT0_LO((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
269 FORCE_RET();
270 }
271
272 void op_mulhiu (void)
273 {
274 set_HIT0_LO((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1);
275 FORCE_RET();
276 }
277
278 void op_mulshi (void)
279 {
280 set_HIT0_LO(0 - ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1));
281 FORCE_RET();
282 }
283
284 void op_mulshiu (void)
285 {
286 set_HIT0_LO(0 - ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1));
287 FORCE_RET();
288 }
289
290 #endif /* TARGET_LONG_BITS > HOST_LONG_BITS */
291
292 /* CP1 functions */
293 #if 0
294 # define DEBUG_FPU_STATE() CALL_FROM_TB1(dump_fpu, env)
295 #else
296 # define DEBUG_FPU_STATE() do { } while(0)
297 #endif
298
299 /* Float support.
300 Single precition routines have a "s" suffix, double precision a
301 "d" suffix, 32bit integer "w", 64bit integer "l", paired singe "ps",
302 paired single lowwer "pl", paired single upper "pu". */
303
304 #define FLOAT_OP(name, p) void OPPROTO op_float_##name##_##p(void)
305
306 FLOAT_OP(pll, ps)
307 {
308 DT2 = ((uint64_t)WT0 << 32) | WT1;
309 DEBUG_FPU_STATE();
310 FORCE_RET();
311 }
312 FLOAT_OP(plu, ps)
313 {
314 DT2 = ((uint64_t)WT0 << 32) | WTH1;
315 DEBUG_FPU_STATE();
316 FORCE_RET();
317 }
318 FLOAT_OP(pul, ps)
319 {
320 DT2 = ((uint64_t)WTH0 << 32) | WT1;
321 DEBUG_FPU_STATE();
322 FORCE_RET();
323 }
324 FLOAT_OP(puu, ps)
325 {
326 DT2 = ((uint64_t)WTH0 << 32) | WTH1;
327 DEBUG_FPU_STATE();
328 FORCE_RET();
329 }
330
331 FLOAT_OP(movf, d)
332 {
333 if (!(env->fpu->fcr31 & PARAM1))
334 DT2 = DT0;
335 DEBUG_FPU_STATE();
336 FORCE_RET();
337 }
338 FLOAT_OP(movf, s)
339 {
340 if (!(env->fpu->fcr31 & PARAM1))
341 WT2 = WT0;
342 DEBUG_FPU_STATE();
343 FORCE_RET();
344 }
345 FLOAT_OP(movf, ps)
346 {
347 unsigned int mask = GET_FP_COND (env->fpu) >> PARAM1;
348 if (!(mask & 1))
349 WT2 = WT0;
350 if (!(mask & 2))
351 WTH2 = WTH0;
352 DEBUG_FPU_STATE();
353 FORCE_RET();
354 }
355 FLOAT_OP(movt, d)
356 {
357 if (env->fpu->fcr31 & PARAM1)
358 DT2 = DT0;
359 DEBUG_FPU_STATE();
360 FORCE_RET();
361 }
362 FLOAT_OP(movt, s)
363 {
364 if (env->fpu->fcr31 & PARAM1)
365 WT2 = WT0;
366 DEBUG_FPU_STATE();
367 FORCE_RET();
368 }
369 FLOAT_OP(movt, ps)
370 {
371 unsigned int mask = GET_FP_COND (env->fpu) >> PARAM1;
372 if (mask & 1)
373 WT2 = WT0;
374 if (mask & 2)
375 WTH2 = WTH0;
376 DEBUG_FPU_STATE();
377 FORCE_RET();
378 }
379 FLOAT_OP(movz, d)
380 {
381 if (!T0)
382 DT2 = DT0;
383 DEBUG_FPU_STATE();
384 FORCE_RET();
385 }
386 FLOAT_OP(movz, s)
387 {
388 if (!T0)
389 WT2 = WT0;
390 DEBUG_FPU_STATE();
391 FORCE_RET();
392 }
393 FLOAT_OP(movz, ps)
394 {
395 if (!T0) {
396 WT2 = WT0;
397 WTH2 = WTH0;
398 }
399 DEBUG_FPU_STATE();
400 FORCE_RET();
401 }
402 FLOAT_OP(movn, d)
403 {
404 if (T0)
405 DT2 = DT0;
406 DEBUG_FPU_STATE();
407 FORCE_RET();
408 }
409 FLOAT_OP(movn, s)
410 {
411 if (T0)
412 WT2 = WT0;
413 DEBUG_FPU_STATE();
414 FORCE_RET();
415 }
416 FLOAT_OP(movn, ps)
417 {
418 if (T0) {
419 WT2 = WT0;
420 WTH2 = WTH0;
421 }
422 DEBUG_FPU_STATE();
423 FORCE_RET();
424 }
425
426 /* ternary operations */
427 #define FLOAT_TERNOP(name1, name2) \
428 FLOAT_OP(name1 ## name2, d) \
429 { \
430 FDT0 = float64_ ## name1 (FDT0, FDT1, &env->fpu->fp_status); \
431 FDT2 = float64_ ## name2 (FDT0, FDT2, &env->fpu->fp_status); \
432 DEBUG_FPU_STATE(); \
433 FORCE_RET(); \
434 } \
435 FLOAT_OP(name1 ## name2, s) \
436 { \
437 FST0 = float32_ ## name1 (FST0, FST1, &env->fpu->fp_status); \
438 FST2 = float32_ ## name2 (FST0, FST2, &env->fpu->fp_status); \
439 DEBUG_FPU_STATE(); \
440 FORCE_RET(); \
441 } \
442 FLOAT_OP(name1 ## name2, ps) \
443 { \
444 FST0 = float32_ ## name1 (FST0, FST1, &env->fpu->fp_status); \
445 FSTH0 = float32_ ## name1 (FSTH0, FSTH1, &env->fpu->fp_status); \
446 FST2 = float32_ ## name2 (FST0, FST2, &env->fpu->fp_status); \
447 FSTH2 = float32_ ## name2 (FSTH0, FSTH2, &env->fpu->fp_status); \
448 DEBUG_FPU_STATE(); \
449 FORCE_RET(); \
450 }
451 FLOAT_TERNOP(mul, add)
452 FLOAT_TERNOP(mul, sub)
453 #undef FLOAT_TERNOP
454
455 /* negated ternary operations */
456 #define FLOAT_NTERNOP(name1, name2) \
457 FLOAT_OP(n ## name1 ## name2, d) \
458 { \
459 FDT0 = float64_ ## name1 (FDT0, FDT1, &env->fpu->fp_status); \
460 FDT2 = float64_ ## name2 (FDT0, FDT2, &env->fpu->fp_status); \
461 FDT2 = float64_chs(FDT2); \
462 DEBUG_FPU_STATE(); \
463 FORCE_RET(); \
464 } \
465 FLOAT_OP(n ## name1 ## name2, s) \
466 { \
467 FST0 = float32_ ## name1 (FST0, FST1, &env->fpu->fp_status); \
468 FST2 = float32_ ## name2 (FST0, FST2, &env->fpu->fp_status); \
469 FST2 = float32_chs(FST2); \
470 DEBUG_FPU_STATE(); \
471 FORCE_RET(); \
472 } \
473 FLOAT_OP(n ## name1 ## name2, ps) \
474 { \
475 FST0 = float32_ ## name1 (FST0, FST1, &env->fpu->fp_status); \
476 FSTH0 = float32_ ## name1 (FSTH0, FSTH1, &env->fpu->fp_status); \
477 FST2 = float32_ ## name2 (FST0, FST2, &env->fpu->fp_status); \
478 FSTH2 = float32_ ## name2 (FSTH0, FSTH2, &env->fpu->fp_status); \
479 FST2 = float32_chs(FST2); \
480 FSTH2 = float32_chs(FSTH2); \
481 DEBUG_FPU_STATE(); \
482 FORCE_RET(); \
483 }
484 FLOAT_NTERNOP(mul, add)
485 FLOAT_NTERNOP(mul, sub)
486 #undef FLOAT_NTERNOP
487
488 /* unary operations, modifying fp status */
489 #define FLOAT_UNOP(name) \
490 FLOAT_OP(name, d) \
491 { \
492 FDT2 = float64_ ## name(FDT0, &env->fpu->fp_status); \
493 DEBUG_FPU_STATE(); \
494 FORCE_RET(); \
495 } \
496 FLOAT_OP(name, s) \
497 { \
498 FST2 = float32_ ## name(FST0, &env->fpu->fp_status); \
499 DEBUG_FPU_STATE(); \
500 FORCE_RET(); \
501 }
502 FLOAT_UNOP(sqrt)
503 #undef FLOAT_UNOP
504
505 /* unary operations, not modifying fp status */
506 #define FLOAT_UNOP(name) \
507 FLOAT_OP(name, d) \
508 { \
509 FDT2 = float64_ ## name(FDT0); \
510 DEBUG_FPU_STATE(); \
511 FORCE_RET(); \
512 } \
513 FLOAT_OP(name, s) \
514 { \
515 FST2 = float32_ ## name(FST0); \
516 DEBUG_FPU_STATE(); \
517 FORCE_RET(); \
518 } \
519 FLOAT_OP(name, ps) \
520 { \
521 FST2 = float32_ ## name(FST0); \
522 FSTH2 = float32_ ## name(FSTH0); \
523 DEBUG_FPU_STATE(); \
524 FORCE_RET(); \
525 }
526 FLOAT_UNOP(abs)
527 FLOAT_UNOP(chs)
528 #undef FLOAT_UNOP
529
530 FLOAT_OP(alnv, ps)
531 {
532 switch (T0 & 0x7) {
533 case 0:
534 FST2 = FST0;
535 FSTH2 = FSTH0;
536 break;
537 case 4:
538 #ifdef TARGET_WORDS_BIGENDIAN
539 FSTH2 = FST0;
540 FST2 = FSTH1;
541 #else
542 FSTH2 = FST1;
543 FST2 = FSTH0;
544 #endif
545 break;
546 default: /* unpredictable */
547 break;
548 }
549 DEBUG_FPU_STATE();
550 FORCE_RET();
551 }
552
553 void op_bc1f (void)
554 {
555 T0 = !!(~GET_FP_COND(env->fpu) & (0x1 << PARAM1));
556 DEBUG_FPU_STATE();
557 FORCE_RET();
558 }
559 void op_bc1any2f (void)
560 {
561 T0 = !!(~GET_FP_COND(env->fpu) & (0x3 << PARAM1));
562 DEBUG_FPU_STATE();
563 FORCE_RET();
564 }
565 void op_bc1any4f (void)
566 {
567 T0 = !!(~GET_FP_COND(env->fpu) & (0xf << PARAM1));
568 DEBUG_FPU_STATE();
569 FORCE_RET();
570 }
571
572 void op_bc1t (void)
573 {
574 T0 = !!(GET_FP_COND(env->fpu) & (0x1 << PARAM1));
575 DEBUG_FPU_STATE();
576 FORCE_RET();
577 }
578 void op_bc1any2t (void)
579 {
580 T0 = !!(GET_FP_COND(env->fpu) & (0x3 << PARAM1));
581 DEBUG_FPU_STATE();
582 FORCE_RET();
583 }
584 void op_bc1any4t (void)
585 {
586 T0 = !!(GET_FP_COND(env->fpu) & (0xf << PARAM1));
587 DEBUG_FPU_STATE();
588 FORCE_RET();
589 }