2 * m68k micro operations
4 * Copyright (c) 2006 CodeSourcery
5 * Written by Paul Brook
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.
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.
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
23 #include "m68k-qreg.h"
26 #define offsetof(type, field) ((size_t) &((type *)0)->field)
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),
37 #define CPU_FP_STATUS env->fp_status
39 #define RAISE_EXCEPTION(n) do { \
40 env->exception_index = n; \
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
51 if (qreg
== QREG_T0
) {
53 } else if (qreg
< TARGET_NUM_QREGS
) {
54 return *(uint32_t *)(((long)env
) + qreg_offsets
[qreg
]);
56 return env
->qregs
[qreg
- TARGET_NUM_QREGS
];
60 void set_op(int qreg
, uint32_t val
)
62 if (qreg
== QREG_T0
) {
64 } else if (qreg
< TARGET_NUM_QREGS
) {
65 *(uint32_t *)(((long)env
) + qreg_offsets
[qreg
]) = val
;
67 env
->qregs
[qreg
- TARGET_NUM_QREGS
] = val
;
71 float64
get_opf64(int qreg
)
73 if (qreg
< TARGET_NUM_QREGS
) {
74 return *(float64
*)(((long)env
) + qreg_offsets
[qreg
]);
76 return *(float64
*)&env
->qregs
[qreg
- TARGET_NUM_QREGS
];
80 void set_opf64(int qreg
, float64 val
)
82 if (qreg
< TARGET_NUM_QREGS
) {
83 *(float64
*)(((long)env
) + qreg_offsets
[qreg
]) = val
;
85 *(float64
*)&env
->qregs
[qreg
- TARGET_NUM_QREGS
] = val
;
89 #define OP(name) void OPPROTO op_##name (void)
93 set_op(PARAM1
, get_op(PARAM2
));
99 set_op(PARAM1
, PARAM2
);
105 set_opf64(PARAM1
, get_opf64(PARAM2
));
111 set_opf64(PARAM1
, 0);
117 uint32_t op2
= get_op(PARAM2
);
118 uint32_t op3
= get_op(PARAM3
);
119 set_op(PARAM1
, op2
+ op3
);
125 uint32_t op2
= get_op(PARAM2
);
126 uint32_t op3
= get_op(PARAM3
);
127 set_op(PARAM1
, op2
- op3
);
133 uint32_t op2
= get_op(PARAM2
);
134 uint32_t op3
= get_op(PARAM3
);
135 set_op(PARAM1
, op2
* op3
);
141 uint32_t arg
= get_op(PARAM2
);
142 set_op(PARAM1
, ~arg
);
148 uint32_t arg
= get_op(PARAM2
);
149 set_op(PARAM1
, -arg
);
155 uint32_t arg
= get_op(PARAM2
);
156 arg
= (arg
>> 24) | (arg
<< 24)
157 | ((arg
>> 16) & 0xff00) | ((arg
<< 16) & 0xff0000);
164 uint32_t op1
= get_op(PARAM1
);
165 uint32_t op2
= get_op(PARAM2
);
167 env
->cc_dest
&= ~CCF_Z
;
169 env
->cc_dest
|= CCF_Z
;
175 uint32_t op1
= get_op(PARAM1
);
176 uint32_t op2
= get_op(PARAM2
);
179 env
->cc_x
= (op1
<= op2
);
180 env
->cc_op
= CC_OP_SUBX
;
181 res
= op1
- (op2
+ 1);
183 env
->cc_x
= (op1
< op2
);
184 env
->cc_op
= CC_OP_SUB
;
193 uint32_t op1
= get_op(PARAM1
);
194 uint32_t op2
= get_op(PARAM2
);
198 env
->cc_x
= (res
<= op2
);
199 env
->cc_op
= CC_OP_ADDX
;
202 env
->cc_x
= (res
< op2
);
203 env
->cc_op
= CC_OP_ADD
;
213 uint32_t op2
= get_op(PARAM2
);
214 uint32_t op3
= get_op(PARAM3
);
215 set_op(PARAM1
, op2
& op3
);
221 uint32_t op2
= get_op(PARAM2
);
222 uint32_t op3
= get_op(PARAM3
);
223 set_op(PARAM1
, op2
| op3
);
229 uint32_t op2
= get_op(PARAM2
);
230 uint32_t op3
= get_op(PARAM3
);
231 set_op(PARAM1
, op2
^ op3
);
238 uint32_t op2
= get_op(PARAM2
);
239 uint32_t op3
= get_op(PARAM3
);
242 set_op(PARAM1
, result
);
248 uint32_t op1
= get_op(PARAM1
);
249 uint32_t op2
= get_op(PARAM2
);
252 set_op(PARAM1
, result
);
253 env
->cc_x
= (op1
<< (op2
- 1)) & 1;
259 uint32_t op2
= get_op(PARAM2
);
260 uint32_t op3
= get_op(PARAM3
);
263 set_op(PARAM1
, result
);
269 uint32_t op1
= get_op(PARAM1
);
270 uint32_t op2
= get_op(PARAM2
);
273 set_op(PARAM1
, result
);
274 env
->cc_x
= (op1
>> (op2
- 1)) & 1;
280 int32_t op1
= get_op(PARAM1
);
281 uint32_t op2
= get_op(PARAM2
);
284 set_op(PARAM1
, result
);
285 env
->cc_x
= (op1
>> (op2
- 1)) & 1;
293 uint32_t op2
= get_op(PARAM2
);
294 set_op(PARAM1
, (uint8_t)op2
);
300 uint32_t op2
= get_op(PARAM2
);
301 set_op(PARAM1
, (int8_t)op2
);
307 uint32_t op2
= get_op(PARAM2
);
308 set_op(PARAM1
, (uint16_t)op2
);
314 uint32_t op2
= get_op(PARAM2
);
315 set_op(PARAM1
, (int16_t)op2
);
319 /* Load/store ops. */
322 uint32_t addr
= get_op(PARAM2
);
323 set_op(PARAM1
, ldub(addr
));
329 uint32_t addr
= get_op(PARAM2
);
330 set_op(PARAM1
, ldsb(addr
));
336 uint32_t addr
= get_op(PARAM2
);
337 set_op(PARAM1
, lduw(addr
));
343 uint32_t addr
= get_op(PARAM2
);
344 set_op(PARAM1
, ldsw(addr
));
350 uint32_t addr
= get_op(PARAM2
);
351 set_op(PARAM1
, ldl(addr
));
357 uint32_t addr
= get_op(PARAM1
);
358 stb(addr
, get_op(PARAM2
));
364 uint32_t addr
= get_op(PARAM1
);
365 stw(addr
, get_op(PARAM2
));
371 uint32_t addr
= get_op(PARAM1
);
372 stl(addr
, get_op(PARAM2
));
378 uint32_t addr
= get_op(PARAM2
);
379 set_opf64(PARAM1
, ldfq(addr
));
385 uint32_t addr
= get_op(PARAM1
);
386 stfq(addr
, get_opf64(PARAM2
));
393 if (cc_op
== CC_OP_DYNAMIC
)
395 cpu_m68k_flush_flags(env
, cc_op
);
409 /* ??? This needs to make sure the throwing location is accurate. */
411 RAISE_EXCEPTION(EXCP_DIV0
);
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
418 if (PARAM1
== 2 && quot
> 0xffff)
422 else if ((int32_t)quot
< 0)
426 env
->cc_dest
= flags
;
441 RAISE_EXCEPTION(EXCP_DIV0
);
445 if (PARAM1
== 2 && quot
!= (int16_t)quot
)
453 env
->cc_dest
= flags
;
459 RAISE_EXCEPTION(PARAM1
);
463 /* Floating point comparison sets flags differently to other instructions. */
469 src0
= get_opf64(PARAM2
);
470 src1
= get_opf64(PARAM3
);
471 set_opf64(PARAM1
, helper_sub_cmpf64(env
, src0
, src1
));
477 uint32_t op1
= get_op(PARAM1
);
484 uint32_t op1
= get_op(PARAM1
);
485 uint32_t op2
= get_op(PARAM2
);
486 env
->cc_x
= (op1
< op2
);
492 set_op(PARAM1
, env
->cc_x
);
498 uint32_t op1
= get_op(PARAM1
);
505 uint32_t op1
= get_op(PARAM1
);
506 uint32_t op2
= get_op(PARAM2
);
514 env
->fp_result
= get_opf64(PARAM1
);
523 /* These ops involve a function call, which probably requires a stack frame
524 and breaks things on some hosts. */
527 uint32_t arg
= get_op(PARAM1
);
535 uint32_t arg
= get_op(PARAM1
);
543 int32_t arg
= get_op(PARAM1
);
551 int32_t arg
= get_op(PARAM1
);
557 void OPPROTO
op_goto_tb0(void)
559 GOTO_TB(op_goto_tb0
, PARAM1
, 0);
562 void OPPROTO
op_goto_tb1(void)
564 GOTO_TB(op_goto_tb1
, PARAM1
, 1);
573 /* Floating point. */
576 set_op(PARAM1
, float64_to_int32(get_opf64(PARAM2
), &CPU_FP_STATUS
));
586 u
.f
= float64_to_float32(get_opf64(PARAM2
), &CPU_FP_STATUS
);
593 set_opf64(PARAM1
, int32_to_float64(get_op(PARAM2
), &CPU_FP_STATUS
));
603 u
.i
= get_op(PARAM2
);
604 set_opf64(PARAM1
, float32_to_float64(u
.f
, &CPU_FP_STATUS
));
610 float64 op0
= get_opf64(PARAM2
);
611 set_opf64(PARAM1
, float64_abs(op0
));
617 float64 op0
= get_opf64(PARAM2
);
618 set_opf64(PARAM1
, float64_chs(op0
));
624 float64 op0
= get_opf64(PARAM2
);
625 set_opf64(PARAM1
, float64_sqrt(op0
, &CPU_FP_STATUS
));
631 float64 op0
= get_opf64(PARAM2
);
632 float64 op1
= get_opf64(PARAM3
);
633 set_opf64(PARAM1
, float64_add(op0
, op1
, &CPU_FP_STATUS
));
639 float64 op0
= get_opf64(PARAM2
);
640 float64 op1
= get_opf64(PARAM3
);
641 set_opf64(PARAM1
, float64_sub(op0
, op1
, &CPU_FP_STATUS
));
647 float64 op0
= get_opf64(PARAM2
);
648 float64 op1
= get_opf64(PARAM3
);
649 set_opf64(PARAM1
, float64_mul(op0
, op1
, &CPU_FP_STATUS
));
655 float64 op0
= get_opf64(PARAM2
);
656 float64 op1
= get_opf64(PARAM3
);
657 set_opf64(PARAM1
, float64_div(op0
, op1
, &CPU_FP_STATUS
));
663 float64 op0
= get_opf64(PARAM2
);
664 set_opf64(PARAM1
, float64_round_to_int(op0
, &CPU_FP_STATUS
));
670 float64 op0
= get_opf64(PARAM2
);
671 set_opf64(PARAM1
, float64_trunc_to_int(op0
, &CPU_FP_STATUS
));
677 float64 op0
= get_opf64(PARAM2
);
678 float64 op1
= get_opf64(PARAM3
);
679 set_op(PARAM1
, float64_compare_quiet(op0
, op1
, &CPU_FP_STATUS
));