]> Git Repo - qemu.git/blob - target-m68k/op.c
M68k system mode semihosting.
[qemu.git] / 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(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 OP(flush_flags)
320 {
321     int cc_op  = PARAM1;
322     if (cc_op == CC_OP_DYNAMIC)
323         cc_op = env->cc_op;
324     cpu_m68k_flush_flags(env, cc_op);
325     FORCE_RET();
326 }
327
328 OP(divu)
329 {
330     uint32_t num;
331     uint32_t den;
332     uint32_t quot;
333     uint32_t rem;
334     uint32_t flags;
335     
336     num = env->div1;
337     den = env->div2;
338     /* ??? This needs to make sure the throwing location is accurate.  */
339     if (den == 0)
340         RAISE_EXCEPTION(EXCP_DIV0);
341     quot = num / den;
342     rem = num % den;
343     flags = 0;
344     /* Avoid using a PARAM1 of zero.  This breaks dyngen because it uses
345        the address of a symbol, and gcc knows symbols can't have address
346        zero.  */
347     if (PARAM1 == 2 && quot > 0xffff)
348         flags |= CCF_V;
349     if (quot == 0)
350         flags |= CCF_Z;
351     else if ((int32_t)quot < 0)
352         flags |= CCF_N;
353     env->div1 = quot;
354     env->div2 = rem;
355     env->cc_dest = flags;
356     FORCE_RET();
357 }
358
359 OP(divs)
360 {
361     int32_t num;
362     int32_t den;
363     int32_t quot;
364     int32_t rem;
365     int32_t flags;
366     
367     num = env->div1;
368     den = env->div2;
369     if (den == 0)
370         RAISE_EXCEPTION(EXCP_DIV0);
371     quot = num / den;
372     rem = num % den;
373     flags = 0;
374     if (PARAM1 == 2 && quot != (int16_t)quot)
375         flags |= CCF_V;
376     if (quot == 0)
377         flags |= CCF_Z;
378     else if (quot < 0)
379         flags |= CCF_N;
380     env->div1 = quot;
381     env->div2 = rem;
382     env->cc_dest = flags;
383     FORCE_RET();
384 }
385
386 /* Halt is special because it may be a semihosting call.  */
387 OP(halt)
388 {
389     RAISE_EXCEPTION(EXCP_HALT_INSN);
390     FORCE_RET();
391 }
392
393 OP(stop)
394 {
395     env->halted = 1;
396     RAISE_EXCEPTION(EXCP_HLT);
397     FORCE_RET();
398 }
399
400 OP(raise_exception)
401 {
402     RAISE_EXCEPTION(PARAM1);
403     FORCE_RET();
404 }
405
406 /* Floating point comparison sets flags differently to other instructions.  */
407
408 OP(sub_cmpf64)
409 {
410     float64 src0;
411     float64 src1;
412     src0 = get_opf64(PARAM2);
413     src1 = get_opf64(PARAM3);
414     set_opf64(PARAM1, helper_sub_cmpf64(env, src0, src1));
415     FORCE_RET();
416 }
417
418 OP(update_xflag_tst)
419 {
420     uint32_t op1 = get_op(PARAM1);
421     env->cc_x = op1;
422     FORCE_RET();
423 }
424
425 OP(update_xflag_lt)
426 {
427     uint32_t op1 = get_op(PARAM1);
428     uint32_t op2 = get_op(PARAM2);
429     env->cc_x = (op1 < op2);
430     FORCE_RET();
431 }
432
433 OP(get_xflag)
434 {
435     set_op(PARAM1, env->cc_x);
436     FORCE_RET();
437 }
438
439 OP(logic_cc)
440 {
441     uint32_t op1 = get_op(PARAM1);
442     env->cc_dest = op1;
443     FORCE_RET();
444 }
445
446 OP(update_cc_add)
447 {
448     uint32_t op1 = get_op(PARAM1);
449     uint32_t op2 = get_op(PARAM2);
450     env->cc_dest = op1;
451     env->cc_src = op2;
452     FORCE_RET();
453 }
454
455 OP(fp_result)
456 {
457     env->fp_result = get_opf64(PARAM1);
458     FORCE_RET();
459 }
460
461 OP(jmp)
462 {
463     GOTO_LABEL_PARAM(1);
464 }
465
466 /* These ops involve a function call, which probably requires a stack frame
467    and breaks things on some hosts.  */
468 OP(jmp_z32)
469 {
470     uint32_t arg = get_op(PARAM1);
471     if (arg == 0)
472         GOTO_LABEL_PARAM(2);
473     FORCE_RET();
474 }
475
476 OP(jmp_nz32)
477 {
478     uint32_t arg = get_op(PARAM1);
479     if (arg != 0)
480         GOTO_LABEL_PARAM(2);
481     FORCE_RET();
482 }
483
484 OP(jmp_s32)
485 {
486     int32_t arg = get_op(PARAM1);
487     if (arg < 0)
488         GOTO_LABEL_PARAM(2);
489     FORCE_RET();
490 }
491
492 OP(jmp_ns32)
493 {
494     int32_t arg = get_op(PARAM1);
495     if (arg >= 0)
496         GOTO_LABEL_PARAM(2);
497     FORCE_RET();
498 }
499
500 void OPPROTO op_goto_tb0(void)
501 {
502     GOTO_TB(op_goto_tb0, PARAM1, 0);
503 }
504
505 void OPPROTO op_goto_tb1(void)
506 {
507     GOTO_TB(op_goto_tb1, PARAM1, 1);
508 }
509
510 OP(exit_tb)
511 {
512     EXIT_TB();
513 }
514
515
516 /* Floating point.  */
517 OP(f64_to_i32)
518 {
519     set_op(PARAM1, float64_to_int32(get_opf64(PARAM2), &CPU_FP_STATUS));
520     FORCE_RET();
521 }
522
523 OP(f64_to_f32)
524 {
525     union {
526         float32 f;
527         uint32_t i;
528     } u;
529     u.f = float64_to_float32(get_opf64(PARAM2), &CPU_FP_STATUS);
530     set_op(PARAM1, u.i);
531     FORCE_RET();
532 }
533
534 OP(i32_to_f64)
535 {
536     set_opf64(PARAM1, int32_to_float64(get_op(PARAM2), &CPU_FP_STATUS));
537     FORCE_RET();
538 }
539
540 OP(f32_to_f64)
541 {
542     union {
543         float32 f;
544         uint32_t i;
545     } u;
546     u.i = get_op(PARAM2);
547     set_opf64(PARAM1, float32_to_float64(u.f, &CPU_FP_STATUS));
548     FORCE_RET();
549 }
550
551 OP(absf64)
552 {
553     float64 op0 = get_opf64(PARAM2);
554     set_opf64(PARAM1, float64_abs(op0));
555     FORCE_RET();
556 }
557
558 OP(chsf64)
559 {
560     float64 op0 = get_opf64(PARAM2);
561     set_opf64(PARAM1, float64_chs(op0));
562     FORCE_RET();
563 }
564
565 OP(sqrtf64)
566 {
567     float64 op0 = get_opf64(PARAM2);
568     set_opf64(PARAM1, float64_sqrt(op0, &CPU_FP_STATUS));
569     FORCE_RET();
570 }
571
572 OP(addf64)
573 {
574     float64 op0 = get_opf64(PARAM2);
575     float64 op1 = get_opf64(PARAM3);
576     set_opf64(PARAM1, float64_add(op0, op1, &CPU_FP_STATUS));
577     FORCE_RET();
578 }
579
580 OP(subf64)
581 {
582     float64 op0 = get_opf64(PARAM2);
583     float64 op1 = get_opf64(PARAM3);
584     set_opf64(PARAM1, float64_sub(op0, op1, &CPU_FP_STATUS));
585     FORCE_RET();
586 }
587
588 OP(mulf64)
589 {
590     float64 op0 = get_opf64(PARAM2);
591     float64 op1 = get_opf64(PARAM3);
592     set_opf64(PARAM1, float64_mul(op0, op1, &CPU_FP_STATUS));
593     FORCE_RET();
594 }
595
596 OP(divf64)
597 {
598     float64 op0 = get_opf64(PARAM2);
599     float64 op1 = get_opf64(PARAM3);
600     set_opf64(PARAM1, float64_div(op0, op1, &CPU_FP_STATUS));
601     FORCE_RET();
602 }
603
604 OP(iround_f64)
605 {
606     float64 op0 = get_opf64(PARAM2);
607     set_opf64(PARAM1, float64_round_to_int(op0, &CPU_FP_STATUS));
608     FORCE_RET();
609 }
610
611 OP(itrunc_f64)
612 {
613     float64 op0 = get_opf64(PARAM2);
614     set_opf64(PARAM1, float64_trunc_to_int(op0, &CPU_FP_STATUS));
615     FORCE_RET();
616 }
617
618 OP(compare_quietf64)
619 {
620     float64 op0 = get_opf64(PARAM2);
621     float64 op1 = get_opf64(PARAM3);
622     set_op(PARAM1, float64_compare_quiet(op0, op1, &CPU_FP_STATUS));
623     FORCE_RET();
624 }
625
626 OP(movec)
627 {
628     int op1 = get_op(PARAM1);
629     uint32_t op2 = get_op(PARAM2);
630     helper_movec(env, op1, op2);
631 }
632
633 /* Memory access.  */
634
635 #define MEMSUFFIX _raw
636 #include "op_mem.h"
637
638 #if !defined(CONFIG_USER_ONLY)
639 #define MEMSUFFIX _user
640 #include "op_mem.h"
641 #define MEMSUFFIX _kernel
642 #include "op_mem.h"
643 #endif
This page took 0.055672 seconds and 4 git commands to generate.