]> git.proxmox.com Git - qemu.git/blob - target-m68k/op.c
34878c0215ab7fae560af039ec2679fc23c225e3
[qemu.git] / target-m68k / op.c
1 /*
2 * m68k micro operations
3 *
4 * Copyright (c) 2006 CodeSourcery
5 * Written by Paul Brook
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22 #include "exec.h"
23 #include "m68k-qreg.h"
24
25 #ifndef offsetof
26 #define offsetof(type, field) ((size_t) &((type *)0)->field)
27 #endif
28
29 static long qreg_offsets[] = {
30 #define DEFO32(name, offset) offsetof(CPUState, offset),
31 #define DEFR(name, reg, mode) -1,
32 #define DEFF64(name, offset) offsetof(CPUState, offset),
33 0,
34 #include "qregs.def"
35 };
36
37 #define CPU_FP_STATUS env->fp_status
38
39 #define RAISE_EXCEPTION(n) do { \
40 env->exception_index = n; \
41 cpu_loop_exit(); \
42 } while(0)
43
44 #define get_op helper_get_op
45 #define set_op helper_set_op
46 #define get_opf64 helper_get_opf64
47 #define set_opf64 helper_set_opf64
48 uint32_t
49 get_op(int qreg)
50 {
51 if (qreg == QREG_T0) {
52 return T0;
53 } else if (qreg < TARGET_NUM_QREGS) {
54 return *(uint32_t *)(((long)env) + qreg_offsets[qreg]);
55 } else {
56 return env->qregs[qreg - TARGET_NUM_QREGS];
57 }
58 }
59
60 void set_op(int qreg, uint32_t val)
61 {
62 if (qreg == QREG_T0) {
63 T0 = val;
64 } else if (qreg < TARGET_NUM_QREGS) {
65 *(uint32_t *)(((long)env) + qreg_offsets[qreg]) = val;
66 } else {
67 env->qregs[qreg - TARGET_NUM_QREGS] = val;
68 }
69 }
70
71 float64 get_opf64(int qreg)
72 {
73 if (qreg < TARGET_NUM_QREGS) {
74 return *(float64 *)(((long)env) + qreg_offsets[qreg]);
75 } else {
76 return *(float64 *)&env->qregs[qreg - TARGET_NUM_QREGS];
77 }
78 }
79
80 void set_opf64(int qreg, float64 val)
81 {
82 if (qreg < TARGET_NUM_QREGS) {
83 *(float64 *)(((long)env) + qreg_offsets[qreg]) = val;
84 } else {
85 *(float64 *)&env->qregs[qreg - TARGET_NUM_QREGS] = val;
86 }
87 }
88
89 #define OP(name) void OPPROTO op_##name (void)
90
91 OP(mov32)
92 {
93 set_op(PARAM1, get_op(PARAM2));
94 FORCE_RET();
95 }
96
97 OP(mov32_im)
98 {
99 set_op(PARAM1, PARAM2);
100 FORCE_RET();
101 }
102
103 OP(movf64)
104 {
105 set_opf64(PARAM1, get_opf64(PARAM2));
106 FORCE_RET();
107 }
108
109 OP(zerof64)
110 {
111 set_opf64(PARAM1, 0);
112 FORCE_RET();
113 }
114
115 OP(add32)
116 {
117 uint32_t op2 = get_op(PARAM2);
118 uint32_t op3 = get_op(PARAM3);
119 set_op(PARAM1, op2 + op3);
120 FORCE_RET();
121 }
122
123 OP(sub32)
124 {
125 uint32_t op2 = get_op(PARAM2);
126 uint32_t op3 = get_op(PARAM3);
127 set_op(PARAM1, op2 - op3);
128 FORCE_RET();
129 }
130
131 OP(mul32)
132 {
133 uint32_t op2 = get_op(PARAM2);
134 uint32_t op3 = get_op(PARAM3);
135 set_op(PARAM1, op2 * op3);
136 FORCE_RET();
137 }
138
139 OP(not32)
140 {
141 uint32_t arg = get_op(PARAM2);
142 set_op(PARAM1, ~arg);
143 FORCE_RET();
144 }
145
146 OP(neg32)
147 {
148 uint32_t arg = get_op(PARAM2);
149 set_op(PARAM1, -arg);
150 FORCE_RET();
151 }
152
153 OP(bswap32)
154 {
155 uint32_t arg = get_op(PARAM2);
156 arg = (arg >> 24) | (arg << 24)
157 | ((arg >> 16) & 0xff00) | ((arg << 16) & 0xff0000);
158 set_op(PARAM1, arg);
159 FORCE_RET();
160 }
161
162 OP(btest)
163 {
164 uint32_t op1 = get_op(PARAM1);
165 uint32_t op2 = get_op(PARAM2);
166 if (op1 & op2)
167 env->cc_dest &= ~CCF_Z;
168 else
169 env->cc_dest |= CCF_Z;
170 FORCE_RET();
171 }
172
173 OP(subx_cc)
174 {
175 uint32_t op1 = get_op(PARAM1);
176 uint32_t op2 = get_op(PARAM2);
177 uint32_t res;
178 if (env->cc_x) {
179 env->cc_x = (op1 <= op2);
180 env->cc_op = CC_OP_SUBX;
181 res = op1 - (op2 + 1);
182 } else {
183 env->cc_x = (op1 < op2);
184 env->cc_op = CC_OP_SUB;
185 res = op1 - op2;
186 }
187 set_op(PARAM1, res);
188 FORCE_RET();
189 }
190
191 OP(addx_cc)
192 {
193 uint32_t op1 = get_op(PARAM1);
194 uint32_t op2 = get_op(PARAM2);
195 uint32_t res;
196 if (env->cc_x) {
197 res = op1 + op2 + 1;
198 env->cc_x = (res <= op2);
199 env->cc_op = CC_OP_ADDX;
200 } else {
201 res = op1 + op2;
202 env->cc_x = (res < op2);
203 env->cc_op = CC_OP_ADD;
204 }
205 set_op(PARAM1, res);
206 FORCE_RET();
207 }
208
209 /* Logic ops. */
210
211 OP(and32)
212 {
213 uint32_t op2 = get_op(PARAM2);
214 uint32_t op3 = get_op(PARAM3);
215 set_op(PARAM1, op2 & op3);
216 FORCE_RET();
217 }
218
219 OP(or32)
220 {
221 uint32_t op2 = get_op(PARAM2);
222 uint32_t op3 = get_op(PARAM3);
223 set_op(PARAM1, op2 | op3);
224 FORCE_RET();
225 }
226
227 OP(xor32)
228 {
229 uint32_t op2 = get_op(PARAM2);
230 uint32_t op3 = get_op(PARAM3);
231 set_op(PARAM1, op2 ^ op3);
232 FORCE_RET();
233 }
234
235 /* Shifts. */
236 OP(shl32)
237 {
238 uint32_t op2 = get_op(PARAM2);
239 uint32_t op3 = get_op(PARAM3);
240 uint32_t result;
241 result = op2 << op3;
242 set_op(PARAM1, result);
243 FORCE_RET();
244 }
245
246 OP(shl_cc)
247 {
248 uint32_t op1 = get_op(PARAM1);
249 uint32_t op2 = get_op(PARAM2);
250 uint32_t result;
251 result = op1 << op2;
252 set_op(PARAM1, result);
253 env->cc_x = (op1 << (op2 - 1)) & 1;
254 FORCE_RET();
255 }
256
257 OP(shr32)
258 {
259 uint32_t op2 = get_op(PARAM2);
260 uint32_t op3 = get_op(PARAM3);
261 uint32_t result;
262 result = op2 >> op3;
263 set_op(PARAM1, result);
264 FORCE_RET();
265 }
266
267 OP(shr_cc)
268 {
269 uint32_t op1 = get_op(PARAM1);
270 uint32_t op2 = get_op(PARAM2);
271 uint32_t result;
272 result = op1 >> op2;
273 set_op(PARAM1, result);
274 env->cc_x = (op1 >> (op2 - 1)) & 1;
275 FORCE_RET();
276 }
277
278 OP(sar_cc)
279 {
280 int32_t op1 = get_op(PARAM1);
281 uint32_t op2 = get_op(PARAM2);
282 uint32_t result;
283 result = op1 >> op2;
284 set_op(PARAM1, result);
285 env->cc_x = (op1 >> (op2 - 1)) & 1;
286 FORCE_RET();
287 }
288
289 /* Value extend. */
290
291 OP(ext8u32)
292 {
293 uint32_t op2 = get_op(PARAM2);
294 set_op(PARAM1, (uint8_t)op2);
295 FORCE_RET();
296 }
297
298 OP(ext8s32)
299 {
300 uint32_t op2 = get_op(PARAM2);
301 set_op(PARAM1, (int8_t)op2);
302 FORCE_RET();
303 }
304
305 OP(ext16u32)
306 {
307 uint32_t op2 = get_op(PARAM2);
308 set_op(PARAM1, (uint16_t)op2);
309 FORCE_RET();
310 }
311
312 OP(ext16s32)
313 {
314 uint32_t op2 = get_op(PARAM2);
315 set_op(PARAM1, (int16_t)op2);
316 FORCE_RET();
317 }
318
319 /* Load/store ops. */
320 OP(ld8u32)
321 {
322 uint32_t addr = get_op(PARAM2);
323 set_op(PARAM1, ldub(addr));
324 FORCE_RET();
325 }
326
327 OP(ld8s32)
328 {
329 uint32_t addr = get_op(PARAM2);
330 set_op(PARAM1, ldsb(addr));
331 FORCE_RET();
332 }
333
334 OP(ld16u32)
335 {
336 uint32_t addr = get_op(PARAM2);
337 set_op(PARAM1, lduw(addr));
338 FORCE_RET();
339 }
340
341 OP(ld16s32)
342 {
343 uint32_t addr = get_op(PARAM2);
344 set_op(PARAM1, ldsw(addr));
345 FORCE_RET();
346 }
347
348 OP(ld32)
349 {
350 uint32_t addr = get_op(PARAM2);
351 set_op(PARAM1, ldl(addr));
352 FORCE_RET();
353 }
354
355 OP(st8)
356 {
357 uint32_t addr = get_op(PARAM1);
358 stb(addr, get_op(PARAM2));
359 FORCE_RET();
360 }
361
362 OP(st16)
363 {
364 uint32_t addr = get_op(PARAM1);
365 stw(addr, get_op(PARAM2));
366 FORCE_RET();
367 }
368
369 OP(st32)
370 {
371 uint32_t addr = get_op(PARAM1);
372 stl(addr, get_op(PARAM2));
373 FORCE_RET();
374 }
375
376 OP(ldf64)
377 {
378 uint32_t addr = get_op(PARAM2);
379 set_opf64(PARAM1, ldfq(addr));
380 FORCE_RET();
381 }
382
383 OP(stf64)
384 {
385 uint32_t addr = get_op(PARAM1);
386 stfq(addr, get_opf64(PARAM2));
387 FORCE_RET();
388 }
389
390 OP(flush_flags)
391 {
392 int cc_op = PARAM1;
393 if (cc_op == CC_OP_DYNAMIC)
394 cc_op = env->cc_op;
395 cpu_m68k_flush_flags(env, cc_op);
396 FORCE_RET();
397 }
398
399 OP(divu)
400 {
401 uint32_t num;
402 uint32_t den;
403 uint32_t quot;
404 uint32_t rem;
405 uint32_t flags;
406
407 num = env->div1;
408 den = env->div2;
409 /* ??? This needs to make sure the throwing location is accurate. */
410 if (den == 0)
411 RAISE_EXCEPTION(EXCP_DIV0);
412 quot = num / den;
413 rem = num % den;
414 flags = 0;
415 /* Avoid using a PARAM1 of zero. This breaks dyngen because it uses
416 the address of a symbol, and gcc knows symbols can't have address
417 zero. */
418 if (PARAM1 == 2 && quot > 0xffff)
419 flags |= CCF_V;
420 if (quot == 0)
421 flags |= CCF_Z;
422 else if ((int32_t)quot < 0)
423 flags |= CCF_N;
424 env->div1 = quot;
425 env->div2 = rem;
426 env->cc_dest = flags;
427 FORCE_RET();
428 }
429
430 OP(divs)
431 {
432 int32_t num;
433 int32_t den;
434 int32_t quot;
435 int32_t rem;
436 int32_t flags;
437
438 num = env->div1;
439 den = env->div2;
440 if (den == 0)
441 RAISE_EXCEPTION(EXCP_DIV0);
442 quot = num / den;
443 rem = num % den;
444 flags = 0;
445 if (PARAM1 == 2 && quot != (int16_t)quot)
446 flags |= CCF_V;
447 if (quot == 0)
448 flags |= CCF_Z;
449 else if (quot < 0)
450 flags |= CCF_N;
451 env->div1 = quot;
452 env->div2 = rem;
453 env->cc_dest = flags;
454 FORCE_RET();
455 }
456
457 OP(raise_exception)
458 {
459 RAISE_EXCEPTION(PARAM1);
460 FORCE_RET();
461 }
462
463 /* Floating point comparison sets flags differently to other instructions. */
464
465 OP(sub_cmpf64)
466 {
467 float64 src0;
468 float64 src1;
469 src0 = get_opf64(PARAM2);
470 src1 = get_opf64(PARAM3);
471 set_opf64(PARAM1, helper_sub_cmpf64(env, src0, src1));
472 FORCE_RET();
473 }
474
475 OP(update_xflag_tst)
476 {
477 uint32_t op1 = get_op(PARAM1);
478 env->cc_x = op1;
479 FORCE_RET();
480 }
481
482 OP(update_xflag_lt)
483 {
484 uint32_t op1 = get_op(PARAM1);
485 uint32_t op2 = get_op(PARAM2);
486 env->cc_x = (op1 < op2);
487 FORCE_RET();
488 }
489
490 OP(get_xflag)
491 {
492 set_op(PARAM1, env->cc_x);
493 FORCE_RET();
494 }
495
496 OP(logic_cc)
497 {
498 uint32_t op1 = get_op(PARAM1);
499 env->cc_dest = op1;
500 FORCE_RET();
501 }
502
503 OP(update_cc_add)
504 {
505 uint32_t op1 = get_op(PARAM1);
506 uint32_t op2 = get_op(PARAM2);
507 env->cc_dest = op1;
508 env->cc_src = op2;
509 FORCE_RET();
510 }
511
512 OP(fp_result)
513 {
514 env->fp_result = get_opf64(PARAM1);
515 FORCE_RET();
516 }
517
518 OP(jmp)
519 {
520 GOTO_LABEL_PARAM(1);
521 }
522
523 /* These ops involve a function call, which probably requires a stack frame
524 and breaks things on some hosts. */
525 OP(jmp_z32)
526 {
527 uint32_t arg = get_op(PARAM1);
528 if (arg == 0)
529 GOTO_LABEL_PARAM(2);
530 FORCE_RET();
531 }
532
533 OP(jmp_nz32)
534 {
535 uint32_t arg = get_op(PARAM1);
536 if (arg != 0)
537 GOTO_LABEL_PARAM(2);
538 FORCE_RET();
539 }
540
541 OP(jmp_s32)
542 {
543 int32_t arg = get_op(PARAM1);
544 if (arg < 0)
545 GOTO_LABEL_PARAM(2);
546 FORCE_RET();
547 }
548
549 OP(jmp_ns32)
550 {
551 int32_t arg = get_op(PARAM1);
552 if (arg >= 0)
553 GOTO_LABEL_PARAM(2);
554 FORCE_RET();
555 }
556
557 void OPPROTO op_goto_tb0(void)
558 {
559 GOTO_TB(op_goto_tb0, PARAM1, 0);
560 }
561
562 void OPPROTO op_goto_tb1(void)
563 {
564 GOTO_TB(op_goto_tb1, PARAM1, 1);
565 }
566
567 OP(exit_tb)
568 {
569 EXIT_TB();
570 }
571
572
573 /* Floating point. */
574 OP(f64_to_i32)
575 {
576 set_op(PARAM1, float64_to_int32(get_opf64(PARAM2), &CPU_FP_STATUS));
577 FORCE_RET();
578 }
579
580 OP(f64_to_f32)
581 {
582 union {
583 float32 f;
584 uint32_t i;
585 } u;
586 u.f = float64_to_float32(get_opf64(PARAM2), &CPU_FP_STATUS);
587 set_op(PARAM1, u.i);
588 FORCE_RET();
589 }
590
591 OP(i32_to_f64)
592 {
593 set_opf64(PARAM1, int32_to_float64(get_op(PARAM2), &CPU_FP_STATUS));
594 FORCE_RET();
595 }
596
597 OP(f32_to_f64)
598 {
599 union {
600 float32 f;
601 uint32_t i;
602 } u;
603 u.i = get_op(PARAM2);
604 set_opf64(PARAM1, float32_to_float64(u.f, &CPU_FP_STATUS));
605 FORCE_RET();
606 }
607
608 OP(absf64)
609 {
610 float64 op0 = get_opf64(PARAM2);
611 set_opf64(PARAM1, float64_abs(op0));
612 FORCE_RET();
613 }
614
615 OP(chsf64)
616 {
617 float64 op0 = get_opf64(PARAM2);
618 set_opf64(PARAM1, float64_chs(op0));
619 FORCE_RET();
620 }
621
622 OP(sqrtf64)
623 {
624 float64 op0 = get_opf64(PARAM2);
625 set_opf64(PARAM1, float64_sqrt(op0, &CPU_FP_STATUS));
626 FORCE_RET();
627 }
628
629 OP(addf64)
630 {
631 float64 op0 = get_opf64(PARAM2);
632 float64 op1 = get_opf64(PARAM3);
633 set_opf64(PARAM1, float64_add(op0, op1, &CPU_FP_STATUS));
634 FORCE_RET();
635 }
636
637 OP(subf64)
638 {
639 float64 op0 = get_opf64(PARAM2);
640 float64 op1 = get_opf64(PARAM3);
641 set_opf64(PARAM1, float64_sub(op0, op1, &CPU_FP_STATUS));
642 FORCE_RET();
643 }
644
645 OP(mulf64)
646 {
647 float64 op0 = get_opf64(PARAM2);
648 float64 op1 = get_opf64(PARAM3);
649 set_opf64(PARAM1, float64_mul(op0, op1, &CPU_FP_STATUS));
650 FORCE_RET();
651 }
652
653 OP(divf64)
654 {
655 float64 op0 = get_opf64(PARAM2);
656 float64 op1 = get_opf64(PARAM3);
657 set_opf64(PARAM1, float64_div(op0, op1, &CPU_FP_STATUS));
658 FORCE_RET();
659 }
660
661 OP(iround_f64)
662 {
663 float64 op0 = get_opf64(PARAM2);
664 set_opf64(PARAM1, float64_round_to_int(op0, &CPU_FP_STATUS));
665 FORCE_RET();
666 }
667
668 OP(itrunc_f64)
669 {
670 float64 op0 = get_opf64(PARAM2);
671 set_opf64(PARAM1, float64_trunc_to_int(op0, &CPU_FP_STATUS));
672 FORCE_RET();
673 }
674
675 OP(compare_quietf64)
676 {
677 float64 op0 = get_opf64(PARAM2);
678 float64 op1 = get_opf64(PARAM3);
679 set_op(PARAM1, float64_compare_quiet(op0, op1, &CPU_FP_STATUS));
680 FORCE_RET();
681 }