Implement ColdFire ff1.
[qemu] / target-m68k / op.c
1 /*
2  *  m68k micro operations
3  * 
4  *  Copyright (c) 2006-2007 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 >= TARGET_NUM_QREGS) {
52         return env->qregs[qreg - TARGET_NUM_QREGS];
53     } else if (qreg == QREG_T0) {
54         return T0;
55     } else {
56         return *(uint32_t *)(((long)env) + qreg_offsets[qreg]);
57     }
58 }
59
60 void set_op(int qreg, uint32_t val)
61 {
62     if (qreg >= TARGET_NUM_QREGS) {
63         env->qregs[qreg - TARGET_NUM_QREGS] = val;
64     } else if (qreg == QREG_T0) {
65         T0 = val;
66     } else {
67         *(uint32_t *)(((long)env) + qreg_offsets[qreg]) = 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 glue(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(ff1)
174 {
175     uint32_t arg = get_op(PARAM2);
176     int n;
177     for (n = 32; arg; n--)
178         arg >>= 1;
179     set_op(PARAM1, n);
180     FORCE_RET();
181 }
182
183 OP(subx_cc)
184 {
185     uint32_t op1 = get_op(PARAM1);
186     uint32_t op2 = get_op(PARAM2);
187     uint32_t res;
188     if (env->cc_x) {
189         env->cc_x = (op1 <= op2);
190         env->cc_op = CC_OP_SUBX;
191         res = op1 - (op2 + 1);
192     } else {
193         env->cc_x = (op1 < op2);
194         env->cc_op = CC_OP_SUB;
195         res = op1 - op2;
196     }
197     set_op(PARAM1, res);
198     FORCE_RET();
199 }
200
201 OP(addx_cc)
202 {
203     uint32_t op1 = get_op(PARAM1);
204     uint32_t op2 = get_op(PARAM2);
205     uint32_t res;
206     if (env->cc_x) {
207         res = op1 + op2 + 1;
208         env->cc_x = (res <= op2);
209         env->cc_op = CC_OP_ADDX;
210     } else {
211         res = op1 + op2;
212         env->cc_x = (res < op2);
213         env->cc_op = CC_OP_ADD;
214     }
215     set_op(PARAM1, res);
216     FORCE_RET();
217 }
218
219 /* Logic ops.  */
220
221 OP(and32)
222 {
223     uint32_t op2 = get_op(PARAM2);
224     uint32_t op3 = get_op(PARAM3);
225     set_op(PARAM1, op2 & op3);
226     FORCE_RET();
227 }
228
229 OP(or32)
230 {
231     uint32_t op2 = get_op(PARAM2);
232     uint32_t op3 = get_op(PARAM3);
233     set_op(PARAM1, op2 | op3);
234     FORCE_RET();
235 }
236
237 OP(xor32)
238 {
239     uint32_t op2 = get_op(PARAM2);
240     uint32_t op3 = get_op(PARAM3);
241     set_op(PARAM1, op2 ^ op3);
242     FORCE_RET();
243 }
244
245 /* Shifts.  */
246 OP(shl32)
247 {
248     uint32_t op2 = get_op(PARAM2);
249     uint32_t op3 = get_op(PARAM3);
250     uint32_t result;
251     result = op2 << op3;
252     set_op(PARAM1, result);
253     FORCE_RET();
254 }
255
256 OP(shl_cc)
257 {
258     uint32_t op1 = get_op(PARAM1);
259     uint32_t op2 = get_op(PARAM2);
260     uint32_t result;
261     result = op1 << op2;
262     set_op(PARAM1, result);
263     env->cc_x = (op1 << (op2 - 1)) & 1;
264     FORCE_RET();
265 }
266
267 OP(shr32)
268 {
269     uint32_t op2 = get_op(PARAM2);
270     uint32_t op3 = get_op(PARAM3);
271     uint32_t result;
272     result = op2 >> op3;
273     set_op(PARAM1, result);
274     FORCE_RET();
275 }
276
277 OP(shr_cc)
278 {
279     uint32_t op1 = get_op(PARAM1);
280     uint32_t op2 = get_op(PARAM2);
281     uint32_t result;
282     result = op1 >> op2;
283     set_op(PARAM1, result);
284     env->cc_x = (op1 >> (op2 - 1)) & 1;
285     FORCE_RET();
286 }
287
288 OP(sar_cc)
289 {
290     int32_t op1 = get_op(PARAM1);
291     uint32_t op2 = get_op(PARAM2);
292     uint32_t result;
293     result = op1 >> op2;
294     set_op(PARAM1, result);
295     env->cc_x = (op1 >> (op2 - 1)) & 1;
296     FORCE_RET();
297 }
298
299 /* Value extend.  */
300
301 OP(ext8u32)
302 {
303     uint32_t op2 = get_op(PARAM2);
304     set_op(PARAM1, (uint8_t)op2);
305     FORCE_RET();
306 }
307
308 OP(ext8s32)
309 {
310     uint32_t op2 = get_op(PARAM2);
311     set_op(PARAM1, (int8_t)op2);
312     FORCE_RET();
313 }
314
315 OP(ext16u32)
316 {
317     uint32_t op2 = get_op(PARAM2);
318     set_op(PARAM1, (uint16_t)op2);
319     FORCE_RET();
320 }
321
322 OP(ext16s32)
323 {
324     uint32_t op2 = get_op(PARAM2);
325     set_op(PARAM1, (int16_t)op2);
326     FORCE_RET();
327 }
328
329 OP(flush_flags)
330 {
331     int cc_op  = PARAM1;
332     if (cc_op == CC_OP_DYNAMIC)
333         cc_op = env->cc_op;
334     cpu_m68k_flush_flags(env, cc_op);
335     FORCE_RET();
336 }
337
338 OP(divu)
339 {
340     uint32_t num;
341     uint32_t den;
342     uint32_t quot;
343     uint32_t rem;
344     uint32_t flags;
345     
346     num = env->div1;
347     den = env->div2;
348     /* ??? This needs to make sure the throwing location is accurate.  */
349     if (den == 0)
350         RAISE_EXCEPTION(EXCP_DIV0);
351     quot = num / den;
352     rem = num % den;
353     flags = 0;
354     /* Avoid using a PARAM1 of zero.  This breaks dyngen because it uses
355        the address of a symbol, and gcc knows symbols can't have address
356        zero.  */
357     if (PARAM1 == 2 && quot > 0xffff)
358         flags |= CCF_V;
359     if (quot == 0)
360         flags |= CCF_Z;
361     else if ((int32_t)quot < 0)
362         flags |= CCF_N;
363     env->div1 = quot;
364     env->div2 = rem;
365     env->cc_dest = flags;
366     FORCE_RET();
367 }
368
369 OP(divs)
370 {
371     int32_t num;
372     int32_t den;
373     int32_t quot;
374     int32_t rem;
375     int32_t flags;
376     
377     num = env->div1;
378     den = env->div2;
379     if (den == 0)
380         RAISE_EXCEPTION(EXCP_DIV0);
381     quot = num / den;
382     rem = num % den;
383     flags = 0;
384     if (PARAM1 == 2 && quot != (int16_t)quot)
385         flags |= CCF_V;
386     if (quot == 0)
387         flags |= CCF_Z;
388     else if (quot < 0)
389         flags |= CCF_N;
390     env->div1 = quot;
391     env->div2 = rem;
392     env->cc_dest = flags;
393     FORCE_RET();
394 }
395
396 /* Halt is special because it may be a semihosting call.  */
397 OP(halt)
398 {
399     RAISE_EXCEPTION(EXCP_HALT_INSN);
400     FORCE_RET();
401 }
402
403 OP(stop)
404 {
405     env->halted = 1;
406     RAISE_EXCEPTION(EXCP_HLT);
407     FORCE_RET();
408 }
409
410 OP(raise_exception)
411 {
412     RAISE_EXCEPTION(PARAM1);
413     FORCE_RET();
414 }
415
416 /* Floating point comparison sets flags differently to other instructions.  */
417
418 OP(sub_cmpf64)
419 {
420     float64 src0;
421     float64 src1;
422     src0 = get_opf64(PARAM2);
423     src1 = get_opf64(PARAM3);
424     set_opf64(PARAM1, helper_sub_cmpf64(env, src0, src1));
425     FORCE_RET();
426 }
427
428 OP(update_xflag_tst)
429 {
430     uint32_t op1 = get_op(PARAM1);
431     env->cc_x = op1;
432     FORCE_RET();
433 }
434
435 OP(update_xflag_lt)
436 {
437     uint32_t op1 = get_op(PARAM1);
438     uint32_t op2 = get_op(PARAM2);
439     env->cc_x = (op1 < op2);
440     FORCE_RET();
441 }
442
443 OP(get_xflag)
444 {
445     set_op(PARAM1, env->cc_x);
446     FORCE_RET();
447 }
448
449 OP(logic_cc)
450 {
451     uint32_t op1 = get_op(PARAM1);
452     env->cc_dest = op1;
453     FORCE_RET();
454 }
455
456 OP(update_cc_add)
457 {
458     uint32_t op1 = get_op(PARAM1);
459     uint32_t op2 = get_op(PARAM2);
460     env->cc_dest = op1;
461     env->cc_src = op2;
462     FORCE_RET();
463 }
464
465 OP(fp_result)
466 {
467     env->fp_result = get_opf64(PARAM1);
468     FORCE_RET();
469 }
470
471 OP(jmp)
472 {
473     GOTO_LABEL_PARAM(1);
474 }
475
476 /* These ops involve a function call, which probably requires a stack frame
477    and breaks things on some hosts.  */
478 OP(jmp_z32)
479 {
480     uint32_t arg = get_op(PARAM1);
481     if (arg == 0)
482         GOTO_LABEL_PARAM(2);
483     FORCE_RET();
484 }
485
486 OP(jmp_nz32)
487 {
488     uint32_t arg = get_op(PARAM1);
489     if (arg != 0)
490         GOTO_LABEL_PARAM(2);
491     FORCE_RET();
492 }
493
494 OP(jmp_s32)
495 {
496     int32_t arg = get_op(PARAM1);
497     if (arg < 0)
498         GOTO_LABEL_PARAM(2);
499     FORCE_RET();
500 }
501
502 OP(jmp_ns32)
503 {
504     int32_t arg = get_op(PARAM1);
505     if (arg >= 0)
506         GOTO_LABEL_PARAM(2);
507     FORCE_RET();
508 }
509
510 void OPPROTO op_goto_tb0(void)
511 {
512     GOTO_TB(op_goto_tb0, PARAM1, 0);
513 }
514
515 void OPPROTO op_goto_tb1(void)
516 {
517     GOTO_TB(op_goto_tb1, PARAM1, 1);
518 }
519
520 OP(exit_tb)
521 {
522     EXIT_TB();
523 }
524
525
526 /* Floating point.  */
527 OP(f64_to_i32)
528 {
529     set_op(PARAM1, float64_to_int32(get_opf64(PARAM2), &CPU_FP_STATUS));
530     FORCE_RET();
531 }
532
533 OP(f64_to_f32)
534 {
535     union {
536         float32 f;
537         uint32_t i;
538     } u;
539     u.f = float64_to_float32(get_opf64(PARAM2), &CPU_FP_STATUS);
540     set_op(PARAM1, u.i);
541     FORCE_RET();
542 }
543
544 OP(i32_to_f64)
545 {
546     set_opf64(PARAM1, int32_to_float64(get_op(PARAM2), &CPU_FP_STATUS));
547     FORCE_RET();
548 }
549
550 OP(f32_to_f64)
551 {
552     union {
553         float32 f;
554         uint32_t i;
555     } u;
556     u.i = get_op(PARAM2);
557     set_opf64(PARAM1, float32_to_float64(u.f, &CPU_FP_STATUS));
558     FORCE_RET();
559 }
560
561 OP(absf64)
562 {
563     float64 op0 = get_opf64(PARAM2);
564     set_opf64(PARAM1, float64_abs(op0));
565     FORCE_RET();
566 }
567
568 OP(chsf64)
569 {
570     float64 op0 = get_opf64(PARAM2);
571     set_opf64(PARAM1, float64_chs(op0));
572     FORCE_RET();
573 }
574
575 OP(sqrtf64)
576 {
577     float64 op0 = get_opf64(PARAM2);
578     set_opf64(PARAM1, float64_sqrt(op0, &CPU_FP_STATUS));
579     FORCE_RET();
580 }
581
582 OP(addf64)
583 {
584     float64 op0 = get_opf64(PARAM2);
585     float64 op1 = get_opf64(PARAM3);
586     set_opf64(PARAM1, float64_add(op0, op1, &CPU_FP_STATUS));
587     FORCE_RET();
588 }
589
590 OP(subf64)
591 {
592     float64 op0 = get_opf64(PARAM2);
593     float64 op1 = get_opf64(PARAM3);
594     set_opf64(PARAM1, float64_sub(op0, op1, &CPU_FP_STATUS));
595     FORCE_RET();
596 }
597
598 OP(mulf64)
599 {
600     float64 op0 = get_opf64(PARAM2);
601     float64 op1 = get_opf64(PARAM3);
602     set_opf64(PARAM1, float64_mul(op0, op1, &CPU_FP_STATUS));
603     FORCE_RET();
604 }
605
606 OP(divf64)
607 {
608     float64 op0 = get_opf64(PARAM2);
609     float64 op1 = get_opf64(PARAM3);
610     set_opf64(PARAM1, float64_div(op0, op1, &CPU_FP_STATUS));
611     FORCE_RET();
612 }
613
614 OP(iround_f64)
615 {
616     float64 op0 = get_opf64(PARAM2);
617     set_opf64(PARAM1, float64_round_to_int(op0, &CPU_FP_STATUS));
618     FORCE_RET();
619 }
620
621 OP(itrunc_f64)
622 {
623     float64 op0 = get_opf64(PARAM2);
624     set_opf64(PARAM1, float64_trunc_to_int(op0, &CPU_FP_STATUS));
625     FORCE_RET();
626 }
627
628 OP(compare_quietf64)
629 {
630     float64 op0 = get_opf64(PARAM2);
631     float64 op1 = get_opf64(PARAM3);
632     set_op(PARAM1, float64_compare_quiet(op0, op1, &CPU_FP_STATUS));
633     FORCE_RET();
634 }
635
636 OP(movec)
637 {
638     int op1 = get_op(PARAM1);
639     uint32_t op2 = get_op(PARAM2);
640     helper_movec(env, op1, op2);
641 }
642
643 /* Memory access.  */
644
645 #define MEMSUFFIX _raw
646 #include "op_mem.h"
647
648 #if !defined(CONFIG_USER_ONLY)
649 #define MEMSUFFIX _user
650 #include "op_mem.h"
651 #define MEMSUFFIX _kernel
652 #include "op_mem.h"
653 #endif